├── .dockerignore
├── .gitignore
├── .php-cs-fixer.php
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── README.md
├── behat.yml
├── bin
└── xmllint
├── composer.json
├── composer.lock
├── phpunit.xml.dist
├── src
└── php
│ ├── bootstrap.php
│ ├── console
│ ├── application
│ │ └── Application.php
│ └── command
│ │ ├── Command.php
│ │ ├── HelpCommand.php
│ │ └── LintCommand.php
│ ├── data
│ ├── FileReport.php
│ └── ValidationProblem.php
│ └── validator
│ ├── LintValidation.php
│ ├── ValidationCollection.php
│ ├── ValidationFactory.php
│ ├── ValidationInterface.php
│ ├── XsdValidation.php
│ └── helper
│ └── LibXmlErrorFormatter.php
├── tests
├── functional
│ ├── _testdata
│ │ ├── broken.xml
│ │ ├── fourtytwo.xml
│ │ ├── logo.svg
│ │ ├── schema.xsd
│ │ ├── with_xsd.xml
│ │ └── with_xsd_broken.xml
│ ├── contexts
│ │ └── FeatureContext.php
│ └── xml-lint.feature
└── unit
│ ├── _testdata
│ ├── comment_first.xml
│ ├── empty.xml
│ ├── empty.xsd
│ ├── with_bad_url_xsd.xml
│ ├── with_empty_xsd.xml
│ └── with_not_existing_xsd.xml
│ ├── bootstrap.inc.php
│ ├── check-coverage.php
│ ├── data
│ ├── FileReportTest.php
│ └── ValidationProblemTest.php
│ └── validator
│ ├── LintValidationTest.php
│ ├── ValidationCollectionTest.php
│ ├── ValidationFactoryTest.php
│ ├── XsdValidationTest.php
│ └── helper
│ └── LibXmlErrorFormatterTest.php
└── tools
└── php-cs-fixer
├── .gitignore
├── composer.json
└── composer.lock
/.dockerignore:
--------------------------------------------------------------------------------
1 | vendor
2 | *.cache
3 | composer.lock
4 | tools/php-cs-fixer/composer.lock
5 | .git
6 | .idea
7 | Dockerfile
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | build/
3 | .idea/
4 | .php-cs-fixer.cache
5 | .phpunit.result.cache
6 |
--------------------------------------------------------------------------------
/.php-cs-fixer.php:
--------------------------------------------------------------------------------
1 | true,
5 | 'array_syntax' => array('syntax' => 'short'),
6 | 'combine_consecutive_unsets' => true,
7 | 'no_useless_else' => true,
8 | 'no_useless_return' => true,
9 | 'ordered_imports' => ['sort_algorithm' => 'length'],
10 | 'concat_space' => [
11 | 'spacing' => 'one',
12 | ],
13 | 'yoda_style' => false,
14 | 'dir_constant' => false,
15 | 'phpdoc_indent' => false,
16 | 'phpdoc_annotation_without_dot' => false,
17 | 'phpdoc_no_empty_return' => true,
18 | 'phpdoc_add_missing_param_annotation' => true,
19 | 'phpdoc_order' => true,
20 | 'phpdoc_types_order' => true,
21 | 'general_phpdoc_annotation_remove' => [
22 | 'annotations' => [
23 | 'author',
24 | ],
25 | ],
26 | 'void_return' => false,
27 | 'single_trait_insert_per_statement' => false,
28 | 'ternary_to_null_coalescing' => true,
29 | 'pow_to_exponentiation' => false,
30 | 'random_api_migration' => false,
31 | 'declare_strict_types' => false,
32 | 'phpdoc_no_alias_tag' => [
33 | 'replacements' => [
34 | 'type' => 'var',
35 | 'link' => 'see',
36 | ],
37 | ],
38 | 'header_comment' => [
39 | 'comment_type' => 'PHPDoc',
40 | 'header' => 'This file is part of the Sclable Xml Lint Package.
41 |
42 | @copyright (c) ' . date('Y') . ' Sclable Business Solutions GmbH
43 |
44 | For the full copyright and license information, please view the LICENSE
45 | file that was distributed with this source code.',
46 | 'location' => 'after_declare_strict',
47 | //'separate' => 'bottom',
48 | ],
49 | ];
50 |
51 | return (new PhpCsFixer\Config())
52 | ->setFinder(
53 | PhpCsFixer\Finder::create()
54 | ->in(__DIR__ . '/src')
55 | ->in(__DIR__ . '/tests')
56 | ->in(__DIR__ . '/bin')
57 | // Note: The pattern is seen relative from one of the `->in()`
58 | // directories. And works for files too this way.
59 | ->notPath('bootstrap.php')
60 | )
61 | ->setRules($fixers);
62 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Sclable XML Lint - Changelog
2 | ============================
3 |
4 | 0.9.0
5 | -----
6 |
7 | * Add support for PHP 8.4
8 | * Drop support for PHP 8.0
9 | * Update dependencies
10 | ============================
11 |
12 | 0.8.0
13 | -----
14 |
15 | * Add support for Symfony 7
16 | * Drop support for Symfony 4
17 | ============================
18 |
19 | 0.7.0
20 | -----
21 |
22 | * Add support for PHP 8.3
23 |
24 | 0.6.0
25 | -----
26 |
27 | * Add support for PHP 8.2
28 | * Drop support for PHP 7.4
29 |
30 | 0.5.0
31 | -----
32 |
33 | * Add support for PHP 8.1
34 | * Drop support for PHP 7.3
35 | * Chores: remove Travis integration
36 |
37 | 0.4.0
38 | -----
39 |
40 | * Add support for PHP 8
41 | * Drop support for PHP 7.2
42 | * Chores: Travis integration update
43 |
44 | 0.3.0
45 | -----
46 |
47 | * Add support for symfony console / finder 5.*
48 | * Drop compatibility for PHP <7.2 and eol symfony versions
49 | * Update test frameworks to latest versions
50 |
51 |
52 | 0.2.4
53 | -----
54 |
55 | * update dependencies to symfony/finder & symfony/console (include 4.*)
56 |
57 |
58 | 0.2.3
59 | -----
60 |
61 | * clean up composer file (move tests to autoload-dev)
62 |
63 | 0.2.2
64 | -----
65 |
66 | * update dependencies to symfony/finder & symfony/console
67 |
68 |
69 | 0.2.1
70 | -----
71 |
72 | * fix a bug where patterns were empty
73 |
74 | 0.2.0
75 | -----
76 |
77 | * validate xml files against XSD schemata (with skip option)
78 | * pattern option
79 |
80 |
81 | 0.1.0
82 | -----
83 |
84 | * cli interface
85 | * lint xml file
86 | * lint files in a directory
87 | * recursive option (default is 'yes')
88 | * exclude option
89 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG PHP_VERSION
2 | FROM php:${PHP_VERSION}-cli-alpine AS dependencies
3 | ARG PHP_CS_FIXER
4 | RUN apk add --update --no-cache zip unzip php-zip
5 | COPY --from=composer /usr/bin/composer /usr/bin/composer
6 | RUN addgroup -S php && adduser -S php -G php \
7 | && mkdir -p /usr/src/xml-lint \
8 | && chown php:php -R /usr/src/xml-lint
9 | WORKDIR /usr/src/xml-lint
10 | COPY --chown=php:php . ./
11 | USER php
12 | RUN composer install --prefer-dist -o -a -n --no-progress \
13 | && \
14 | if [[ -n "${PHP_CS_FIXER}" ]]; then \
15 | composer install --working-dir=tools/php-cs-fixer --prefer-dist -o -a -n --no-progress; \
16 | fi
17 |
18 | FROM php:${PHP_VERSION}-cli-alpine AS test
19 | ARG PHP_CS_FIXER
20 | RUN addgroup -S php && adduser -S php -G php \
21 | && mkdir -p /usr/src/xml-lint \
22 | && chown php:php -R /usr/src/xml-lint
23 |
24 | WORKDIR /usr/src/xml-lint
25 | COPY --from=dependencies --chown=php:php /usr/src/xml-lint ./
26 | USER php
27 |
28 | RUN if [[ -n "${PHP_CS_FIXER}" ]]; then \
29 | php tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run -v; \
30 | fi
31 | RUN php vendor/bin/phpunit
32 | RUN php vendor/bin/behat
33 |
34 | FROM dependencies AS build_production
35 | WORKDIR /usr/src/xml-lint
36 |
37 | RUN rm -rf tools/ tests/ \
38 | && composer install --prefer-dist -o -a -n --no-progress --no-dev
39 |
40 | FROM php:${PHP_VERSION}-cli-alpine AS production
41 | WORKDIR /usr/src/xml-lint
42 | COPY --from=build_production /usr/src/xml-lint ./
43 | RUN ln -s /usr/src/xml-lint/bin/xmllint /usr/bin/xml-lint
44 | WORKDIR /usr/src
45 | ENTRYPOINT ["php", "/usr/src/xml-lint/bin/xmllint"]
46 | CMD ["--help"]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Sclable Business Solutions GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Sclable XML Lint
2 | ================
3 |
4 | A php tool to lint and validate xml files from the commandline.
5 |
6 | [](https://travis-ci.com/sclable/xml-lint) [](//packagist.org/packages/sclable/xml-lint) [](//packagist.org/packages/sclable/xml-lint) [](//packagist.org/packages/sclable/xml-lint)
7 |
8 | XML Lint checks the syntax of any xml files and validates the file against the XSD schema defined in the file.
9 |
10 | Usage
11 | -----
12 |
13 | ### Installation with Composer
14 |
15 | If you'd like to include this library in your project with [composer](https://getcomposer.org/), simply run:
16 |
17 | composer require "sclable/xml-lint"
18 |
19 | ### Command Line Usage
20 |
21 | To lint a single xml file:
22 |
23 | vendor/bin/xmllint path/to/file.xml
24 |
25 | To lint a directory and all its subdirectories:
26 |
27 | vendor/bin/xmllint path/to/dir
28 |
29 | #### Help
30 |
31 | `xmllint` has built in cli help screen:
32 |
33 | vendor/bin/xmllint --help
34 |
35 | #### Options
36 |
37 | * `-v` be verbose, display the filename of the current file to lint
38 | * `-r 0` don't search recursive (if the argument is a directory)
39 | * `-e name` exclude files or directories containing 'name'
40 | * `-s` skip the xsd validation
41 |
42 |
43 | Development
44 | -----------
45 |
46 | ### Run tests
47 |
48 | ```shell
49 | # check code style
50 | php tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run -v
51 |
52 | # run tests
53 | php vendor/bin/phpunit
54 | php vendor/bin/behat
55 | ```
56 |
57 | Using docker:
58 |
59 | ```shell
60 | # Example
61 | docker build -t xml-lint:php-8.4 --build-arg=PHP_VERSION="8.4" .
62 |
63 | # PHP_VERSION: choose between 8.1, 8.2, 8.3 and 8.4
64 | docker build -t xml-lint:php-8.1 --build-arg=PHP_VERSION="8.1" .
65 | docker build -t xml-lint:php-8.2 --build-arg=PHP_VERSION="8.2" .
66 | docker build -t xml-lint:php-8.3 --build-arg=PHP_VERSION="8.3" .
67 | docker build -t xml-lint:php-8.4 --build-arg=PHP_VERSION="8.4" .
68 |
69 | # Run with code style check
70 | docker build -t xml-lint:php-8.4 --build-arg=PHP_VERSION="8.4" --build-arg=PHP_CS_FIXER=true .
71 |
72 | # Use this image to run xml-lint:
73 | cd tests/functional/_testdata
74 | docker run -it --rm -v "$PWD":/var/src -w /var/src xml-lint:php-8.4 -r -v -- ./
75 | ```
76 |
77 |
78 | Changelog
79 | ---------
80 |
81 | For the changelog see the [CHANGELOG](CHANGELOG) file
82 |
83 | License
84 | -------
85 |
86 | For the license and copyright see the [LICENSE](LICENSE) file
87 |
--------------------------------------------------------------------------------
/behat.yml:
--------------------------------------------------------------------------------
1 | # behat configuration
2 | default:
3 | suites:
4 | default:
5 | paths: [ "%paths.base%/tests/functional" ]
6 | contexts: [ sclable\xmlLint\tests\functional\contexts\FeatureContext ]
7 |
--------------------------------------------------------------------------------
/bin/xmllint:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | run();
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sclable/xml-lint",
3 | "description": "A php cli tool to lint and validate xml files.",
4 | "license": "MIT",
5 | "authors": [
6 | {
7 | "name": "Michael Rutz",
8 | "email": "michael.rutz@sclable.com"
9 | },
10 | {
11 | "name": "Hakan Özkan",
12 | "email": "hakan.ozkan@sclable.com"
13 | }
14 | ],
15 | "keywords": [
16 | "xml",
17 | "lint",
18 | "cli",
19 | "xsd",
20 | "xml schema"
21 | ],
22 | "bin": ["bin/xmllint"],
23 | "require": {
24 | "php": "8.1.*|8.2.*|8.3.*|8.4.*",
25 | "symfony/console": "5.3.*|5.4.*|6.*|7.*",
26 | "symfony/finder": "5.3.*|5.4.*|6.*|7.*",
27 | "ext-libxml": "*",
28 | "ext-dom": "*"
29 | },
30 | "require-dev": {
31 | "behat/behat": "^3.0",
32 | "phpunit/phpunit": "^10"
33 | },
34 | "autoload": {
35 | "psr-4": {
36 | "sclable\\xmlLint\\": "src/php/"
37 | }
38 | },
39 | "autoload-dev": {
40 | "psr-4": {
41 | "sclable\\xmlLint\\tests\\": "tests/"
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | tests/unit
6 |
7 |
8 |
9 |
10 | src/php/
11 |
12 |
13 | src/php/console/
14 | src/php/bootstrap.php
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/php/bootstrap.php:
--------------------------------------------------------------------------------
1 | setDefaultCommand(LintCommand::COMMAND_NAME);
37 | }
38 |
39 | protected function getDefaultCommands(): array
40 | {
41 | parent::getDefaultCommands();
42 |
43 | return [
44 | new HelpCommand(),
45 | new LintCommand(),
46 | ];
47 | }
48 |
49 | /**
50 | * @SuppressWarnings(PHPMD.Superglobals)
51 | */
52 | public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
53 | {
54 | if (null === $input) {
55 | // rewrite the input for single command usage
56 | $argv = $_SERVER['argv'];
57 | $scriptName = array_shift($argv);
58 | array_unshift($argv, 'lint');
59 | array_unshift($argv, $scriptName);
60 | $input = new ArgvInput($argv);
61 | }
62 |
63 | return parent::run($input, $output);
64 | }
65 |
66 | protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output): int
67 | {
68 | if ('version' != $command->getName()) {
69 | $output->writeln($this->getLongVersion());
70 | }
71 |
72 | return parent::doRunCommand($command, $input, $output);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/php/console/command/Command.php:
--------------------------------------------------------------------------------
1 | synopsis[$key])) {
32 | $this->synopsis[$key] = trim(sprintf(
33 | '%s %s',
34 | $_SERVER['PHP_SELF'],
35 | $this->getDefinition()->getSynopsis($short)
36 | ));
37 | }
38 |
39 | return $this->synopsis[$key];
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/php/console/command/HelpCommand.php:
--------------------------------------------------------------------------------
1 | [--option|-o] `
24 | * customized: `xmllint [--option|-o] `
25 | *
26 | * @see \Symfony\Component\Console\Command\HelpCommand
27 | */
28 | class HelpCommand extends \Symfony\Component\Console\Command\HelpCommand
29 | {
30 | protected function configure()
31 | {
32 | $this->ignoreValidationErrors();
33 |
34 | $this
35 | ->setName('help')
36 | ->setDefinition([
37 | new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
38 | new InputOption(
39 | 'format',
40 | null,
41 | InputOption::VALUE_REQUIRED,
42 | 'The output format (txt, xml, json, or md)',
43 | 'txt'
44 | ),
45 | new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
46 | ])
47 | ->setDescription('Display help')
48 | ->setHelp(<<%command.name% command displays the help.
50 | You can also output the help in other formats by using the --format option:
51 |
52 | php %command.full_name% --help --format=xml
53 | EOF
54 | );
55 | }
56 |
57 | protected function execute(InputInterface $input, OutputInterface $output): int
58 | {
59 | $this->setCommand(
60 | $this->getApplication()->find(LintCommand::COMMAND_NAME)
61 | );
62 |
63 | return parent::execute($input, $output);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/php/console/command/LintCommand.php:
--------------------------------------------------------------------------------
1 | setName(self::COMMAND_NAME)
59 | ->setDescription('lint an xml file')
60 | ->addArgument(
61 | self::ARGUMENT_FILE,
62 | InputArgument::REQUIRED,
63 | 'the path/to/file.xml to lint a single file or a path/to/directory to lint all xml ' .
64 | 'files in a directory.'
65 | )
66 | ->addOption(
67 | self::OPTION_RECURSIVE,
68 | 'r',
69 | InputOption::VALUE_OPTIONAL,
70 | 'Whether to scan directories recursive.',
71 | true
72 | )
73 | ->addOption(
74 | self::OPTION_EXCLUDE,
75 | 'e',
76 | InputOption::VALUE_REQUIRED,
77 | 'Path(s) to exclude from linting, can be several separated by comma'
78 | )
79 | ->addOption(
80 | self::OPTION_PATTERN,
81 | 'p',
82 | InputOption::VALUE_REQUIRED,
83 | 'Filter files with one or more patterns, e.g.: *.svg,*.xml. Separate patterns by comma.'
84 | )
85 | ->addOption(
86 | self::OPTION_NO_XSD,
87 | 's',
88 | InputOption::VALUE_NONE,
89 | 'Skip downloading and checking against XSD-files.'
90 | )
91 | ;
92 | }
93 |
94 | protected function execute(InputInterface $input, OutputInterface $output): int
95 | {
96 | $this->start = microtime(true);
97 | $this->output = $output;
98 | $this->input = $input;
99 |
100 | if ($input->getOption(self::OPTION_NO_XSD)) {
101 | $this->validator = ValidationFactory::createLintOnlyValidation();
102 | } else {
103 | $this->validator = ValidationFactory::createDefaultCollection();
104 | }
105 |
106 | $file = $input->getArgument(self::ARGUMENT_FILE);
107 |
108 | $output->writeln('progress: ');
109 | if (is_dir($file)) {
110 | $status = $this->lintDir($file);
111 | } else {
112 | $status = $this->lintFile(new \SplFileInfo($file));
113 | }
114 |
115 | $output->writeln('');
116 |
117 | if (false === $status) {
118 | $this->printReportsOfFilesWithProblems();
119 | }
120 |
121 | $this->output->writeln(sprintf(
122 | PHP_EOL . '%d files / %1.2f seconds done',
123 | count($this->reports),
124 | microtime(true) - $this->start
125 | ));
126 |
127 | return $status ? 0 : 1;
128 | }
129 |
130 | /**
131 | * lint the content of a directory, recursive if defined.
132 | *
133 | * @param string $dir path/to/dir
134 | *
135 | * @return bool
136 | */
137 | private function lintDir($dir)
138 | {
139 | $finder = Finder::create();
140 | $finder->files()
141 | ->in($dir);
142 |
143 | $patterns = $this->input->getOption(self::OPTION_PATTERN);
144 | if (!empty($patterns)) {
145 | $patterns = explode(',', $patterns);
146 | foreach ($patterns as $pattern) {
147 | $finder->name(trim($pattern));
148 | }
149 | } else {
150 | $finder->name('*.xml.dist')
151 | ->name('*.xml');
152 | }
153 |
154 | if (!$this->input->getOption(self::OPTION_RECURSIVE)) {
155 | $finder->depth(0);
156 | }
157 |
158 | if ($this->input->hasOption(self::OPTION_EXCLUDE)) {
159 | $exclude = explode(',', (string) $this->input->getOption(self::OPTION_EXCLUDE));
160 | $finder->exclude($exclude);
161 | }
162 |
163 | $totalFiles = $finder->count();
164 |
165 | $counter = 0;
166 | $ret = true;
167 | /** @var SplFileInfo $file */
168 | foreach ($finder as $file) {
169 | $ret = $this->lintFile($file) && $ret;
170 | if (0 == ++$counter % 30) {
171 | $this->output->writeln(sprintf(
172 | ' %8d/%d %6.2f%%',
173 | $counter,
174 | $totalFiles,
175 | $counter / $totalFiles * 100
176 | ));
177 | }
178 | }
179 |
180 | return $ret;
181 | }
182 |
183 | /**
184 | * format and print the errors from the queue to the output.
185 | */
186 | private function printReportsOfFilesWithProblems()
187 | {
188 | $this->output->writeln(PHP_EOL . 'errors:');
189 |
190 | foreach ($this->reports as $report) {
191 | if (false === $report->hasProblems()) {
192 | continue;
193 | }
194 |
195 | $file = $report->getFile();
196 | $this->output->writeln('file: ' . $file->getPath() . DIRECTORY_SEPARATOR . $file->getFilename());
197 |
198 | foreach ($report->getProblems() as $problem) {
199 | $this->output->write(
200 | ' > ' . $problem->getMessage() . PHP_EOL
201 | );
202 | }
203 |
204 | $this->output->write(' - - ' . PHP_EOL);
205 | }
206 | }
207 |
208 | /**
209 | * lint a file, pass errors to the queue.
210 | *
211 | * @return bool
212 | */
213 | private function lintFile(\SplFileInfo $file)
214 | {
215 | if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
216 | $this->output->write('lint file ' . $file . ' ... ');
217 | }
218 |
219 | $report = FileReport::create($file);
220 | $this->reports[] = $report;
221 | $status = $this->validator->validateFile($report);
222 |
223 | if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
224 | if (false === $status) {
225 | $this->output->writeln('errors');
226 | } else {
227 | $this->output->writeln('passed.');
228 | }
229 | } else {
230 | if (false === $status) {
231 | $this->output->write('F');
232 | } else {
233 | $this->output->write('.');
234 | }
235 | }
236 |
237 | return $status;
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/src/php/data/FileReport.php:
--------------------------------------------------------------------------------
1 | file = $file;
31 | }
32 |
33 | /**
34 | * @param \SplFileInfo|string $file
35 | *
36 | * @return static
37 | */
38 | public static function create($file)
39 | {
40 | if (false === ($file instanceof \SplFileInfo)) {
41 | $file = new \SplFileInfo($file);
42 | }
43 |
44 | return new static($file);
45 | }
46 |
47 | /**
48 | * @param string $msg
49 | *
50 | * @return $this
51 | */
52 | public function reportProblem($msg)
53 | {
54 | $this->addProblem(ValidationProblem::create($msg));
55 |
56 | return $this;
57 | }
58 |
59 | /**
60 | * report a problem to a file.
61 | *
62 | * @return $this
63 | */
64 | public function addProblem(ValidationProblem $problem)
65 | {
66 | $this->problems[] = $problem;
67 |
68 | return $this;
69 | }
70 |
71 | /**
72 | * indicate whether a file has any reported problems or not.
73 | *
74 | * @return bool
75 | */
76 | public function hasProblems()
77 | {
78 | return !empty($this->problems);
79 | }
80 |
81 | /**
82 | * @return \SplFileInfo
83 | */
84 | public function getFile()
85 | {
86 | return $this->file;
87 | }
88 |
89 | /**
90 | * @return ValidationProblem[]
91 | */
92 | public function getProblems()
93 | {
94 | return $this->problems;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/php/data/ValidationProblem.php:
--------------------------------------------------------------------------------
1 | msg = $message;
42 | }
43 |
44 | /**
45 | * @return string
46 | */
47 | public function getMessage()
48 | {
49 | return $this->msg;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/php/validator/LintValidation.php:
--------------------------------------------------------------------------------
1 | formatter = $formatter;
31 | libxml_use_internal_errors(true);
32 | }
33 |
34 | public function validateFile(FileReport $report)
35 | {
36 | $realPath = $report->getFile()->getRealPath();
37 |
38 | if (false === is_file($realPath)) {
39 | $report->reportProblem('file not found: ' . $realPath);
40 |
41 | return false;
42 | }
43 |
44 | if (false === is_readable($realPath)) {
45 | $report->reportProblem('file not readable: ' . $realPath);
46 |
47 | return false;
48 | }
49 |
50 | libxml_clear_errors();
51 | $domDoc = new \DOMDocument();
52 | $domDoc->load($realPath, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_PEDANTIC);
53 |
54 | $errors = libxml_get_errors();
55 | foreach ($this->formatter->formatErrors($errors) as $problem) {
56 | $report->reportProblem($problem);
57 | }
58 |
59 | return !$report->hasProblems();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/php/validator/ValidationCollection.php:
--------------------------------------------------------------------------------
1 | collection as $validation) {
28 | $status = $validation->validateFile($report) && $status;
29 | }
30 |
31 | return $status;
32 | }
33 |
34 | public function addValidation(ValidationInterface $validation)
35 | {
36 | $this->collection[] = $validation;
37 |
38 | return $this;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/php/validator/ValidationFactory.php:
--------------------------------------------------------------------------------
1 | addValidation(new LintValidation($formatter))
31 | ->addValidation(new XsdValidation($formatter));
32 |
33 | return $collection;
34 | }
35 |
36 | /**
37 | * @return ValidationInterface
38 | */
39 | public static function createLintOnlyValidation()
40 | {
41 | $formatter = new LibXmlErrorFormatter();
42 |
43 | return new LintValidation($formatter);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/php/validator/ValidationInterface.php:
--------------------------------------------------------------------------------
1 | formatter = $formatter;
34 | libxml_use_internal_errors(true);
35 | }
36 |
37 | public function validateFile(FileReport $report)
38 | {
39 | $file = $report->getFile()->getRealPath();
40 |
41 | if (empty($file)) {
42 | return false;
43 | }
44 |
45 | $domDoc = new \DOMDocument();
46 | $loaded = $domDoc->load($file, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_PEDANTIC);
47 |
48 | if (false === $loaded) {
49 | return false;
50 | }
51 |
52 | $validation = $this->getSchemaValidationFile($domDoc);
53 |
54 | if (false === $validation) {
55 | return true;
56 | }
57 |
58 | $validationSource = $this->getSchemaValidationSource($validation, $report);
59 |
60 | if (false === $validationSource) {
61 | return false;
62 | }
63 |
64 | libxml_clear_errors();
65 | if (true !== $domDoc->schemaValidateSource($validationSource)) {
66 | $errors = libxml_get_errors();
67 | foreach ($this->formatter->formatErrors($errors) as $problem) {
68 | $report->reportProblem($problem);
69 | }
70 |
71 | return false;
72 | }
73 |
74 | return true;
75 | }
76 |
77 | /**
78 | * @param string $filename
79 | * @param FileReport $report
80 | *
81 | * @return bool|string
82 | */
83 | private function getSchemaValidationSource($filename, $report)
84 | {
85 | if (0 === preg_match('/^(http|https|ftp):/i', $filename)) {
86 | if (false === file_exists($filename)) {
87 | $filename = $report->getFile()->getPath() . '/' . $filename;
88 | }
89 | if (!is_readable($filename)) {
90 | $report->reportProblem('unable to validate, schema file is not readable: ' . $filename);
91 |
92 | return false;
93 | }
94 | }
95 |
96 | if (isset($this->cache[$filename])) {
97 | return $this->cache[$filename];
98 | }
99 |
100 | $validationSource = @file_get_contents($filename);
101 |
102 | if (false === $validationSource) {
103 | $report->reportProblem('unable to load schema file from: ' . $filename);
104 |
105 | return false;
106 | }
107 |
108 | if (empty($validationSource)) {
109 | $report->reportProblem(sprintf('xsd validation file is empty ("%s").', $filename));
110 |
111 | return false;
112 | }
113 |
114 | return $this->cache[$filename] = $validationSource;
115 | }
116 |
117 | /**
118 | * @return bool|string
119 | */
120 | private function getSchemaValidationFile(\DOMDocument $document)
121 | {
122 | $firstChild = $this->getFirstChild($document);
123 | // @codeCoverageIgnoreStart
124 | if (false === $firstChild) {
125 | return false;
126 | }
127 | // @codeCoverageIgnoreEnd
128 |
129 | $attribute = $firstChild->getAttribute('xsi:noNamespaceSchemaLocation');
130 |
131 | if (empty($attribute)) {
132 | return false;
133 | }
134 |
135 | return $attribute;
136 | }
137 |
138 | /**
139 | * @return bool|\DOMElement
140 | */
141 | private function getFirstChild(\DOMDocument $document)
142 | {
143 | foreach ($document->childNodes as $child) {
144 | if ($child instanceof \DOMElement) {
145 | return $child;
146 | // @codeCoverageIgnoreStart
147 | }
148 | }
149 |
150 | return false;
151 | // @codeCoverageIgnoreEnd
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/php/validator/helper/LibXmlErrorFormatter.php:
--------------------------------------------------------------------------------
1 | format($xmlError);
26 | }
27 |
28 | return array_unique($messages);
29 | }
30 |
31 | private function format($xmlError)
32 | {
33 | return sprintf(
34 | $this->format,
35 | $xmlError->line,
36 | $xmlError->code,
37 | trim($xmlError->message)
38 | );
39 | }
40 |
41 | public function setFormat($format)
42 | {
43 | $this->format = $format;
44 |
45 | return $this;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/functional/_testdata/broken.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/tests/functional/_testdata/fourtytwo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | unknown
6 | 42
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/functional/_testdata/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/tests/functional/_testdata/schema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/functional/_testdata/with_xsd.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | unknown
7 | 42
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/functional/_testdata/with_xsd_broken.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | unknown
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/functional/contexts/FeatureContext.php:
--------------------------------------------------------------------------------
1 | application = new Application();
46 |
47 | $command = $this->application->find('lint');
48 |
49 | $this->commandTester = new CommandTester($command);
50 | }
51 |
52 | /**
53 | * @Given the file :file
54 | */
55 | public function theFile($file)
56 | {
57 | $this->file = dirname(__DIR__) . '/_testdata/' . $file;
58 | }
59 |
60 | /**
61 | * @When I run lint
62 | */
63 | public function iRunLint()
64 | {
65 | $this->exitCode = $this->commandTester->execute([
66 | 'file' => $this->file,
67 | ]);
68 | }
69 |
70 | /**
71 | * @Then I have a return code :code
72 | *
73 | * @throws \Exception
74 | */
75 | public function iHaveAReturnCode($code)
76 | {
77 | $code = (int) $code;
78 |
79 | if (null === $this->exitCode) {
80 | echo $this->commandTester->getDisplay();
81 | throw new \Exception('the return code was NULL.');
82 | }
83 |
84 | if ($this->exitCode !== $code) {
85 | echo $this->commandTester->getDisplay();
86 | throw new \Exception(sprintf("the return code does not match. \n Expected: %s\n Actual: %s", $code, $this->exitCode));
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/tests/functional/xml-lint.feature:
--------------------------------------------------------------------------------
1 | Feature: Check an xml file whether its structure seems to be ok or not.
2 |
3 | Scenario: Check and confirm a file to be ok
4 | Given the file "fourtytwo.xml"
5 | When I run lint
6 | Then I have a return code "0"
7 |
8 | Scenario: Check a file with a missing close tag
9 | Given the file "broken.xml"
10 | When I run lint
11 | Then I have a return code "1"
12 |
13 | Scenario: Check a file with an xsd schema validation
14 | Given the file "with_xsd_broken.xml"
15 | When I run lint
16 | Then I have a return code "1"
17 |
18 |
--------------------------------------------------------------------------------
/tests/unit/_testdata/comment_first.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/unit/_testdata/empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/unit/_testdata/empty.xsd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sclable/xml-lint/b114ace41c9b99eb291898f8b67b7063b5b8e884/tests/unit/_testdata/empty.xsd
--------------------------------------------------------------------------------
/tests/unit/_testdata/with_bad_url_xsd.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | unknown
7 | 42
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/unit/_testdata/with_empty_xsd.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | unknown
7 | 42
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/unit/_testdata/with_not_existing_xsd.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | unknown
7 | 42
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/unit/bootstrap.inc.php:
--------------------------------------------------------------------------------
1 | xpath('//metrics');
31 | $totalElements = 0;
32 | $checkedElements = 0;
33 |
34 | foreach ($metrics as $metric) {
35 | $totalElements += (int) $metric['elements'];
36 | $checkedElements += (int) $metric['coveredelements'];
37 | }
38 |
39 | $coverage = ($checkedElements / $totalElements) * 100;
40 |
41 | if ($coverage < $percentage) {
42 | echo 'Code coverage is ' . $coverage . '%, which is below the accepted ' . $percentage . '%' . PHP_EOL;
43 | exit(1);
44 | }
45 |
46 | echo 'Code coverage is ' . $coverage . '% - OK!' . PHP_EOL;
47 |
--------------------------------------------------------------------------------
/tests/unit/data/FileReportTest.php:
--------------------------------------------------------------------------------
1 | assertFalse($report->hasProblems());
27 | }
28 |
29 | public function testHasProblemsReturnsTrueOnProblems()
30 | {
31 | $report = new FileReport(new \SplFileInfo('no_file.xml'));
32 | $problem = $this->getMockBuilder(ValidationProblem::class)
33 | ->disableOriginalConstructor()
34 | ->getMock();
35 |
36 | /* @var ValidationProblem $problem */
37 | $report->addProblem($problem);
38 | $this->assertTrue($report->hasProblems());
39 | }
40 |
41 | public function testCreateFromString()
42 | {
43 | $report = FileReport::create('no_file.xml');
44 | $this->assertInstanceOf(FileReport::class, $report);
45 | }
46 |
47 | public function testReportProblemCreatesValidationProblem()
48 | {
49 | $report = FileReport::create('test_file.xml');
50 | $report->reportProblem('my_message');
51 | $result = $report->getProblems();
52 | $problem = reset($result);
53 |
54 | $this->assertInstanceOf(ValidationProblem::class, $problem);
55 | $this->assertEquals('my_message', $problem->getMessage());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/unit/data/ValidationProblemTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($msg, $problem->getMessage());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/unit/validator/LintValidationTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(FileReport::class)
32 | ->onlyMethods(['reportProblem'])
33 | ->setConstructorArgs([$file])
34 | ->getMock();
35 | $mock->expects($this->exactly(0))
36 | ->method('reportProblem');
37 |
38 | /** @var FileReport $mock */
39 | $return = $validator->validateFile($mock);
40 | $this->assertTrue($return);
41 | }
42 |
43 | public function testReportProblemsForInvalidFile()
44 | {
45 | $validator = new LintValidation(new LibXmlErrorFormatter());
46 |
47 | $filename = dirname(dirname(__DIR__)) . '/functional/_testdata/broken.xml';
48 | $file = new \SplFileInfo($filename);
49 |
50 | $mock = $this->getMockBuilder(FileReport::class)
51 | ->onlyMethods(['reportProblem', 'hasProblems'])
52 | ->setConstructorArgs([$file])
53 | ->getMock();
54 | $mock->method('hasProblems')->willReturn(true);
55 | $mock->expects($this->exactly(3))
56 | ->method('reportProblem');
57 |
58 | /** @var FileReport $mock */
59 | $return = $validator->validateFile($mock);
60 | $this->assertFalse($return);
61 | }
62 |
63 | public function testReportExceptionTextIfNoErrorsAvailable()
64 | {
65 | $validator = new LintValidation(new LibXmlErrorFormatter());
66 |
67 | $file = new \SplFileInfo('does_not_exist.xml');
68 |
69 | $mock = $this->getMockBuilder(FileReport::class)
70 | ->onlyMethods(['reportProblem'])
71 | ->setConstructorArgs([$file])
72 | ->getMock();
73 | $mock->expects($this->exactly(1))
74 | ->method('reportProblem');
75 |
76 | /** @var FileReport $mock */
77 | $return = $validator->validateFile($mock);
78 | $this->assertFalse($return);
79 | }
80 |
81 | public function testReportXmlFileNotReadable()
82 | {
83 | $validator = new LintValidation(new LibXmlErrorFormatter());
84 | $filename = dirname(dirname(__DIR__)) . '/functional/_testdata/fourtytwo.xml';
85 | $file = new \SplFileInfo($filename);
86 | $fileMod = $file->getPerms();
87 | try {
88 | chmod($filename, 0333);
89 | $mock = $this->getMockBuilder(FileReport::class)
90 | ->onlyMethods(['reportProblem'])
91 | ->setConstructorArgs([$file])
92 | ->getMock();
93 | $mock->expects($this->once())
94 | ->method('reportProblem')
95 | ->with('file not readable: ' . $file->getRealPath());
96 |
97 | /** @var FileReport $mock */
98 | $return = $validator->validateFile($mock);
99 | $this->assertFalse($return);
100 | } finally {
101 | chmod($filename, $fileMod);
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/tests/unit/validator/ValidationCollectionTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(ValidationInterface::class)
34 | ->getMock();
35 | $mock2 = $this->getMockBuilder(ValidationInterface::class)
36 | ->getMock();
37 |
38 | $mock1->method('validateFile')
39 | ->willReturn($return1);
40 | $mock2->method('validateFile')
41 | ->willReturn($return2);
42 |
43 | $collection = new ValidationCollection();
44 | /* @var ValidationInterface $mock1 */
45 | /* @var ValidationInterface $mock2 */
46 | $collection->addValidation($mock1)
47 | ->addValidation($mock2);
48 |
49 | $this->assertEquals($expected, $collection->validateFile(FileReport::create('some_file.xml')));
50 | }
51 |
52 | public static function getMockReturnValues()
53 | {
54 | return [
55 | [true, true, true],
56 | [false, false, false],
57 | [false, true, false],
58 | [true, false, false],
59 | ];
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tests/unit/validator/ValidationFactoryTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(ValidationInterface::class, $collection);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/unit/validator/XsdValidationTest.php:
--------------------------------------------------------------------------------
1 | validateFile($report);
35 |
36 | $this->assertFalse($report->hasProblems());
37 | }
38 |
39 | public function testValidateCorruptFileWithXsd()
40 | {
41 | $file = new \SplFileInfo(
42 | dirname(dirname(__DIR__)) . '/functional/_testdata/with_xsd_broken.xml'
43 | );
44 | $report = new FileReport($file);
45 |
46 | $validator = new XsdValidation(new LibXmlErrorFormatter());
47 | $validator->validateFile($report);
48 |
49 | $this->assertTrue($report->hasProblems());
50 | }
51 |
52 | public function testSkipNotExistingFile()
53 | {
54 | $file = new \SplFileInfo('not_exists.xml');
55 |
56 | $mock = $this->getMockBuilder(FileReport::class)
57 | ->onlyMethods(['reportProblem'])
58 | ->setConstructorArgs([$file])
59 | ->getMock();
60 | $mock->expects($this->exactly(0))
61 | ->method('reportProblem');
62 |
63 | $validator = new XsdValidation(new LibXmlErrorFormatter());
64 | /* @var FileReport $mock */
65 | $this->assertFalse($validator->validateFile($mock));
66 | }
67 |
68 | public function testSkipFileWithoutXsd()
69 | {
70 | $file = new \SplFileInfo(
71 | dirname(dirname(__DIR__)) . '/functional/_testdata/fourtytwo.xml'
72 | );
73 | $report = new FileReport($file);
74 |
75 | $validator = new XsdValidation(new LibXmlErrorFormatter());
76 | $return = $validator->validateFile($report);
77 |
78 | $this->assertTrue($return);
79 | $this->assertFalse($report->hasProblems());
80 | }
81 |
82 | public function testReportNonExistingSchemaFile()
83 | {
84 | $file = new \SplFileInfo(
85 | dirname(__DIR__) . '/_testdata/with_not_existing_xsd.xml'
86 | );
87 |
88 | $mock = $this->getMockBuilder(FileReport::class)
89 | ->onlyMethods(['reportProblem', 'hasProblems'])
90 | ->setConstructorArgs([$file])
91 | ->getMock();
92 | $mock->method('hasProblems')->willReturn(true);
93 | $mock->expects($this->once())
94 | ->method('reportProblem')
95 | ->with(
96 | 'unable to validate, schema file is not readable: '
97 | . dirname(__DIR__) . '/_testdata/i_dont_exist.xsd'
98 | );
99 |
100 | $validator = new XsdValidation(new LibXmlErrorFormatter());
101 | /* @var FileReport $mock */
102 | $this->assertFalse($validator->validateFile($mock));
103 | }
104 |
105 | /**
106 | * @covers ::
107 | */
108 | public function testUseInternalCache()
109 | {
110 | $file = new \SplFileInfo(
111 | dirname(dirname(__DIR__)) . '/functional/_testdata/with_xsd.xml'
112 | );
113 | $report = new FileReport($file);
114 | $validator = new XsdValidation(new LibXmlErrorFormatter());
115 | $this->assertTrue($validator->validateFile($report));
116 | $this->assertFalse($report->hasProblems());
117 | $this->assertTrue($validator->validateFile($report));
118 | }
119 |
120 | /**
121 | * @covers ::
122 | */
123 | public function testEmptyXml()
124 | {
125 | $file = new \SplFileInfo(
126 | dirname(__DIR__) . '/_testdata/empty.xml'
127 | );
128 |
129 | $report = new FileReport($file);
130 | $validator = new XsdValidation(new LibXmlErrorFormatter());
131 | $this->assertFalse($validator->validateFile($report));
132 | }
133 |
134 | /**
135 | * @covers ::
136 | */
137 | public function testEmptyXsd()
138 | {
139 | $file = new \SplFileInfo(
140 | dirname(__DIR__) . '/_testdata/with_empty_xsd.xml'
141 | );
142 |
143 | $mock = $this->getMockBuilder(FileReport::class)
144 | ->onlyMethods(['reportProblem', 'hasProblems'])
145 | ->setConstructorArgs([$file])
146 | ->getMock();
147 | $mock->method('hasProblems')->willReturn(true);
148 | $mock->expects($this->once())
149 | ->method('reportProblem')
150 | ->with($this->stringContains('xsd validation file is empty'));
151 |
152 | $validator = new XsdValidation(new LibXmlErrorFormatter());
153 | /* @var FileReport $mock */
154 | $this->assertFalse($validator->validateFile($mock));
155 | }
156 |
157 | /**
158 | * @covers ::
159 | */
160 | public function testDeadUrlXsd()
161 | {
162 | $file = new \SplFileInfo(
163 | dirname(__DIR__) . '/_testdata/with_bad_url_xsd.xml'
164 | );
165 |
166 | $mock = $this->getMockBuilder(FileReport::class)
167 | ->onlyMethods(['reportProblem', 'hasProblems'])
168 | ->setConstructorArgs([$file])
169 | ->getMock();
170 | $mock->method('hasProblems')->willReturn(true);
171 | $mock->expects($this->once())
172 | ->method('reportProblem')
173 | ->with($this->stringContains('unable to load schema file from'));
174 |
175 | $validator = new XsdValidation(new LibXmlErrorFormatter());
176 | /* @var FileReport $mock */
177 | $this->assertFalse($validator->validateFile($mock));
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/tests/unit/validator/helper/LibXmlErrorFormatterTest.php:
--------------------------------------------------------------------------------
1 | createLibXmlError('test', 1, 2)];
25 | $this->assertEquals(
26 | [
27 | 'Line 2: [1] test',
28 | ],
29 | (new LibXmlErrorFormatter())->formatErrors($errors)
30 | );
31 | }
32 |
33 | public function testCustomFormatError()
34 | {
35 | $errors = [$this->createLibXmlError('test', 1, 2)];
36 | $formatter = new LibXmlErrorFormatter();
37 | $formatter->setFormat('%s / %s / %s');
38 | $this->assertEquals(
39 | [
40 | '2 / 1 / test',
41 | ],
42 | $formatter->formatErrors($errors)
43 | );
44 | }
45 |
46 | public function testFilterDuplicates()
47 | {
48 | $errors = [
49 | $this->createLibXmlError('test', 1, 2),
50 | $this->createLibXmlError('test', 1, 2),
51 | ];
52 |
53 | $this->assertCount(1, (new LibXmlErrorFormatter())->formatErrors($errors));
54 | }
55 |
56 | /**
57 | * @param string $msg
58 | * @param int $code
59 | * @param int $line
60 | *
61 | * @return \LibXMLError
62 | */
63 | private function createLibXmlError($msg, $code, $line)
64 | {
65 | $error = new \LibXMLError();
66 | $error->message = $msg;
67 | $error->code = $code;
68 | $error->line = $line;
69 |
70 | return $error;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/tools/php-cs-fixer/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !composer.json
3 | !composer.lock
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/tools/php-cs-fixer/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require": {
3 | "friendsofphp/php-cs-fixer": "^3.85.1"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/tools/php-cs-fixer/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": "077616d4e173da34e81d12fb9dc2e424",
8 | "packages": [
9 | {
10 | "name": "clue/ndjson-react",
11 | "version": "v1.3.0",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/clue/reactphp-ndjson.git",
15 | "reference": "392dc165fce93b5bb5c637b67e59619223c931b0"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0",
20 | "reference": "392dc165fce93b5bb5c637b67e59619223c931b0",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": ">=5.3",
25 | "react/stream": "^1.2"
26 | },
27 | "require-dev": {
28 | "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35",
29 | "react/event-loop": "^1.2"
30 | },
31 | "type": "library",
32 | "autoload": {
33 | "psr-4": {
34 | "Clue\\React\\NDJson\\": "src/"
35 | }
36 | },
37 | "notification-url": "https://packagist.org/downloads/",
38 | "license": [
39 | "MIT"
40 | ],
41 | "authors": [
42 | {
43 | "name": "Christian Lück",
44 | "email": "christian@clue.engineering"
45 | }
46 | ],
47 | "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.",
48 | "homepage": "https://github.com/clue/reactphp-ndjson",
49 | "keywords": [
50 | "NDJSON",
51 | "json",
52 | "jsonlines",
53 | "newline",
54 | "reactphp",
55 | "streaming"
56 | ],
57 | "support": {
58 | "issues": "https://github.com/clue/reactphp-ndjson/issues",
59 | "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0"
60 | },
61 | "funding": [
62 | {
63 | "url": "https://clue.engineering/support",
64 | "type": "custom"
65 | },
66 | {
67 | "url": "https://github.com/clue",
68 | "type": "github"
69 | }
70 | ],
71 | "time": "2022-12-23T10:58:28+00:00"
72 | },
73 | {
74 | "name": "composer/pcre",
75 | "version": "3.3.2",
76 | "source": {
77 | "type": "git",
78 | "url": "https://github.com/composer/pcre.git",
79 | "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
80 | },
81 | "dist": {
82 | "type": "zip",
83 | "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
84 | "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
85 | "shasum": ""
86 | },
87 | "require": {
88 | "php": "^7.4 || ^8.0"
89 | },
90 | "conflict": {
91 | "phpstan/phpstan": "<1.11.10"
92 | },
93 | "require-dev": {
94 | "phpstan/phpstan": "^1.12 || ^2",
95 | "phpstan/phpstan-strict-rules": "^1 || ^2",
96 | "phpunit/phpunit": "^8 || ^9"
97 | },
98 | "type": "library",
99 | "extra": {
100 | "phpstan": {
101 | "includes": [
102 | "extension.neon"
103 | ]
104 | },
105 | "branch-alias": {
106 | "dev-main": "3.x-dev"
107 | }
108 | },
109 | "autoload": {
110 | "psr-4": {
111 | "Composer\\Pcre\\": "src"
112 | }
113 | },
114 | "notification-url": "https://packagist.org/downloads/",
115 | "license": [
116 | "MIT"
117 | ],
118 | "authors": [
119 | {
120 | "name": "Jordi Boggiano",
121 | "email": "j.boggiano@seld.be",
122 | "homepage": "http://seld.be"
123 | }
124 | ],
125 | "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
126 | "keywords": [
127 | "PCRE",
128 | "preg",
129 | "regex",
130 | "regular expression"
131 | ],
132 | "support": {
133 | "issues": "https://github.com/composer/pcre/issues",
134 | "source": "https://github.com/composer/pcre/tree/3.3.2"
135 | },
136 | "funding": [
137 | {
138 | "url": "https://packagist.com",
139 | "type": "custom"
140 | },
141 | {
142 | "url": "https://github.com/composer",
143 | "type": "github"
144 | },
145 | {
146 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
147 | "type": "tidelift"
148 | }
149 | ],
150 | "time": "2024-11-12T16:29:46+00:00"
151 | },
152 | {
153 | "name": "composer/semver",
154 | "version": "3.4.3",
155 | "source": {
156 | "type": "git",
157 | "url": "https://github.com/composer/semver.git",
158 | "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
159 | },
160 | "dist": {
161 | "type": "zip",
162 | "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
163 | "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
164 | "shasum": ""
165 | },
166 | "require": {
167 | "php": "^5.3.2 || ^7.0 || ^8.0"
168 | },
169 | "require-dev": {
170 | "phpstan/phpstan": "^1.11",
171 | "symfony/phpunit-bridge": "^3 || ^7"
172 | },
173 | "type": "library",
174 | "extra": {
175 | "branch-alias": {
176 | "dev-main": "3.x-dev"
177 | }
178 | },
179 | "autoload": {
180 | "psr-4": {
181 | "Composer\\Semver\\": "src"
182 | }
183 | },
184 | "notification-url": "https://packagist.org/downloads/",
185 | "license": [
186 | "MIT"
187 | ],
188 | "authors": [
189 | {
190 | "name": "Nils Adermann",
191 | "email": "naderman@naderman.de",
192 | "homepage": "http://www.naderman.de"
193 | },
194 | {
195 | "name": "Jordi Boggiano",
196 | "email": "j.boggiano@seld.be",
197 | "homepage": "http://seld.be"
198 | },
199 | {
200 | "name": "Rob Bast",
201 | "email": "rob.bast@gmail.com",
202 | "homepage": "http://robbast.nl"
203 | }
204 | ],
205 | "description": "Semver library that offers utilities, version constraint parsing and validation.",
206 | "keywords": [
207 | "semantic",
208 | "semver",
209 | "validation",
210 | "versioning"
211 | ],
212 | "support": {
213 | "irc": "ircs://irc.libera.chat:6697/composer",
214 | "issues": "https://github.com/composer/semver/issues",
215 | "source": "https://github.com/composer/semver/tree/3.4.3"
216 | },
217 | "funding": [
218 | {
219 | "url": "https://packagist.com",
220 | "type": "custom"
221 | },
222 | {
223 | "url": "https://github.com/composer",
224 | "type": "github"
225 | },
226 | {
227 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
228 | "type": "tidelift"
229 | }
230 | ],
231 | "time": "2024-09-19T14:15:21+00:00"
232 | },
233 | {
234 | "name": "composer/xdebug-handler",
235 | "version": "3.0.5",
236 | "source": {
237 | "type": "git",
238 | "url": "https://github.com/composer/xdebug-handler.git",
239 | "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
240 | },
241 | "dist": {
242 | "type": "zip",
243 | "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
244 | "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
245 | "shasum": ""
246 | },
247 | "require": {
248 | "composer/pcre": "^1 || ^2 || ^3",
249 | "php": "^7.2.5 || ^8.0",
250 | "psr/log": "^1 || ^2 || ^3"
251 | },
252 | "require-dev": {
253 | "phpstan/phpstan": "^1.0",
254 | "phpstan/phpstan-strict-rules": "^1.1",
255 | "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
256 | },
257 | "type": "library",
258 | "autoload": {
259 | "psr-4": {
260 | "Composer\\XdebugHandler\\": "src"
261 | }
262 | },
263 | "notification-url": "https://packagist.org/downloads/",
264 | "license": [
265 | "MIT"
266 | ],
267 | "authors": [
268 | {
269 | "name": "John Stevenson",
270 | "email": "john-stevenson@blueyonder.co.uk"
271 | }
272 | ],
273 | "description": "Restarts a process without Xdebug.",
274 | "keywords": [
275 | "Xdebug",
276 | "performance"
277 | ],
278 | "support": {
279 | "irc": "ircs://irc.libera.chat:6697/composer",
280 | "issues": "https://github.com/composer/xdebug-handler/issues",
281 | "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
282 | },
283 | "funding": [
284 | {
285 | "url": "https://packagist.com",
286 | "type": "custom"
287 | },
288 | {
289 | "url": "https://github.com/composer",
290 | "type": "github"
291 | },
292 | {
293 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
294 | "type": "tidelift"
295 | }
296 | ],
297 | "time": "2024-05-06T16:37:16+00:00"
298 | },
299 | {
300 | "name": "evenement/evenement",
301 | "version": "v3.0.2",
302 | "source": {
303 | "type": "git",
304 | "url": "https://github.com/igorw/evenement.git",
305 | "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
306 | },
307 | "dist": {
308 | "type": "zip",
309 | "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
310 | "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
311 | "shasum": ""
312 | },
313 | "require": {
314 | "php": ">=7.0"
315 | },
316 | "require-dev": {
317 | "phpunit/phpunit": "^9 || ^6"
318 | },
319 | "type": "library",
320 | "autoload": {
321 | "psr-4": {
322 | "Evenement\\": "src/"
323 | }
324 | },
325 | "notification-url": "https://packagist.org/downloads/",
326 | "license": [
327 | "MIT"
328 | ],
329 | "authors": [
330 | {
331 | "name": "Igor Wiedler",
332 | "email": "igor@wiedler.ch"
333 | }
334 | ],
335 | "description": "Événement is a very simple event dispatching library for PHP",
336 | "keywords": [
337 | "event-dispatcher",
338 | "event-emitter"
339 | ],
340 | "support": {
341 | "issues": "https://github.com/igorw/evenement/issues",
342 | "source": "https://github.com/igorw/evenement/tree/v3.0.2"
343 | },
344 | "time": "2023-08-08T05:53:35+00:00"
345 | },
346 | {
347 | "name": "fidry/cpu-core-counter",
348 | "version": "1.2.0",
349 | "source": {
350 | "type": "git",
351 | "url": "https://github.com/theofidry/cpu-core-counter.git",
352 | "reference": "8520451a140d3f46ac33042715115e290cf5785f"
353 | },
354 | "dist": {
355 | "type": "zip",
356 | "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f",
357 | "reference": "8520451a140d3f46ac33042715115e290cf5785f",
358 | "shasum": ""
359 | },
360 | "require": {
361 | "php": "^7.2 || ^8.0"
362 | },
363 | "require-dev": {
364 | "fidry/makefile": "^0.2.0",
365 | "fidry/php-cs-fixer-config": "^1.1.2",
366 | "phpstan/extension-installer": "^1.2.0",
367 | "phpstan/phpstan": "^1.9.2",
368 | "phpstan/phpstan-deprecation-rules": "^1.0.0",
369 | "phpstan/phpstan-phpunit": "^1.2.2",
370 | "phpstan/phpstan-strict-rules": "^1.4.4",
371 | "phpunit/phpunit": "^8.5.31 || ^9.5.26",
372 | "webmozarts/strict-phpunit": "^7.5"
373 | },
374 | "type": "library",
375 | "autoload": {
376 | "psr-4": {
377 | "Fidry\\CpuCoreCounter\\": "src/"
378 | }
379 | },
380 | "notification-url": "https://packagist.org/downloads/",
381 | "license": [
382 | "MIT"
383 | ],
384 | "authors": [
385 | {
386 | "name": "Théo FIDRY",
387 | "email": "theo.fidry@gmail.com"
388 | }
389 | ],
390 | "description": "Tiny utility to get the number of CPU cores.",
391 | "keywords": [
392 | "CPU",
393 | "core"
394 | ],
395 | "support": {
396 | "issues": "https://github.com/theofidry/cpu-core-counter/issues",
397 | "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0"
398 | },
399 | "funding": [
400 | {
401 | "url": "https://github.com/theofidry",
402 | "type": "github"
403 | }
404 | ],
405 | "time": "2024-08-06T10:04:20+00:00"
406 | },
407 | {
408 | "name": "friendsofphp/php-cs-fixer",
409 | "version": "v3.85.1",
410 | "source": {
411 | "type": "git",
412 | "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
413 | "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba"
414 | },
415 | "dist": {
416 | "type": "zip",
417 | "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2fb6d7f6c3398dca5786a1635b27405d73a417ba",
418 | "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba",
419 | "shasum": ""
420 | },
421 | "require": {
422 | "clue/ndjson-react": "^1.3",
423 | "composer/semver": "^3.4",
424 | "composer/xdebug-handler": "^3.0.5",
425 | "ext-filter": "*",
426 | "ext-hash": "*",
427 | "ext-json": "*",
428 | "ext-tokenizer": "*",
429 | "fidry/cpu-core-counter": "^1.2",
430 | "php": "^7.4 || ^8.0",
431 | "react/child-process": "^0.6.6",
432 | "react/event-loop": "^1.5",
433 | "react/promise": "^3.2",
434 | "react/socket": "^1.16",
435 | "react/stream": "^1.4",
436 | "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
437 | "symfony/console": "^5.4.47 || ^6.4.13 || ^7.0",
438 | "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0",
439 | "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0",
440 | "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0",
441 | "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0",
442 | "symfony/polyfill-mbstring": "^1.32",
443 | "symfony/polyfill-php80": "^1.32",
444 | "symfony/polyfill-php81": "^1.32",
445 | "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2",
446 | "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0"
447 | },
448 | "require-dev": {
449 | "facile-it/paraunit": "^1.3.1 || ^2.6",
450 | "infection/infection": "^0.29.14",
451 | "justinrainbow/json-schema": "^5.3 || ^6.4",
452 | "keradus/cli-executor": "^2.2",
453 | "mikey179/vfsstream": "^1.6.12",
454 | "php-coveralls/php-coveralls": "^2.8",
455 | "php-cs-fixer/accessible-object": "^1.1",
456 | "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
457 | "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
458 | "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25",
459 | "symfony/polyfill-php84": "^1.32",
460 | "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1",
461 | "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1"
462 | },
463 | "suggest": {
464 | "ext-dom": "For handling output formats in XML",
465 | "ext-mbstring": "For handling non-UTF8 characters."
466 | },
467 | "bin": [
468 | "php-cs-fixer"
469 | ],
470 | "type": "application",
471 | "autoload": {
472 | "psr-4": {
473 | "PhpCsFixer\\": "src/"
474 | },
475 | "exclude-from-classmap": [
476 | "src/Fixer/Internal/*"
477 | ]
478 | },
479 | "notification-url": "https://packagist.org/downloads/",
480 | "license": [
481 | "MIT"
482 | ],
483 | "authors": [
484 | {
485 | "name": "Fabien Potencier",
486 | "email": "fabien@symfony.com"
487 | },
488 | {
489 | "name": "Dariusz Rumiński",
490 | "email": "dariusz.ruminski@gmail.com"
491 | }
492 | ],
493 | "description": "A tool to automatically fix PHP code style",
494 | "keywords": [
495 | "Static code analysis",
496 | "fixer",
497 | "standards",
498 | "static analysis"
499 | ],
500 | "support": {
501 | "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
502 | "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.85.1"
503 | },
504 | "funding": [
505 | {
506 | "url": "https://github.com/keradus",
507 | "type": "github"
508 | }
509 | ],
510 | "time": "2025-07-29T22:22:50+00:00"
511 | },
512 | {
513 | "name": "psr/container",
514 | "version": "2.0.2",
515 | "source": {
516 | "type": "git",
517 | "url": "https://github.com/php-fig/container.git",
518 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
519 | },
520 | "dist": {
521 | "type": "zip",
522 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
523 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
524 | "shasum": ""
525 | },
526 | "require": {
527 | "php": ">=7.4.0"
528 | },
529 | "type": "library",
530 | "extra": {
531 | "branch-alias": {
532 | "dev-master": "2.0.x-dev"
533 | }
534 | },
535 | "autoload": {
536 | "psr-4": {
537 | "Psr\\Container\\": "src/"
538 | }
539 | },
540 | "notification-url": "https://packagist.org/downloads/",
541 | "license": [
542 | "MIT"
543 | ],
544 | "authors": [
545 | {
546 | "name": "PHP-FIG",
547 | "homepage": "https://www.php-fig.org/"
548 | }
549 | ],
550 | "description": "Common Container Interface (PHP FIG PSR-11)",
551 | "homepage": "https://github.com/php-fig/container",
552 | "keywords": [
553 | "PSR-11",
554 | "container",
555 | "container-interface",
556 | "container-interop",
557 | "psr"
558 | ],
559 | "support": {
560 | "issues": "https://github.com/php-fig/container/issues",
561 | "source": "https://github.com/php-fig/container/tree/2.0.2"
562 | },
563 | "time": "2021-11-05T16:47:00+00:00"
564 | },
565 | {
566 | "name": "psr/event-dispatcher",
567 | "version": "1.0.0",
568 | "source": {
569 | "type": "git",
570 | "url": "https://github.com/php-fig/event-dispatcher.git",
571 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
572 | },
573 | "dist": {
574 | "type": "zip",
575 | "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
576 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
577 | "shasum": ""
578 | },
579 | "require": {
580 | "php": ">=7.2.0"
581 | },
582 | "type": "library",
583 | "extra": {
584 | "branch-alias": {
585 | "dev-master": "1.0.x-dev"
586 | }
587 | },
588 | "autoload": {
589 | "psr-4": {
590 | "Psr\\EventDispatcher\\": "src/"
591 | }
592 | },
593 | "notification-url": "https://packagist.org/downloads/",
594 | "license": [
595 | "MIT"
596 | ],
597 | "authors": [
598 | {
599 | "name": "PHP-FIG",
600 | "homepage": "http://www.php-fig.org/"
601 | }
602 | ],
603 | "description": "Standard interfaces for event handling.",
604 | "keywords": [
605 | "events",
606 | "psr",
607 | "psr-14"
608 | ],
609 | "support": {
610 | "issues": "https://github.com/php-fig/event-dispatcher/issues",
611 | "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
612 | },
613 | "time": "2019-01-08T18:20:26+00:00"
614 | },
615 | {
616 | "name": "psr/log",
617 | "version": "3.0.2",
618 | "source": {
619 | "type": "git",
620 | "url": "https://github.com/php-fig/log.git",
621 | "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
622 | },
623 | "dist": {
624 | "type": "zip",
625 | "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
626 | "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
627 | "shasum": ""
628 | },
629 | "require": {
630 | "php": ">=8.0.0"
631 | },
632 | "type": "library",
633 | "extra": {
634 | "branch-alias": {
635 | "dev-master": "3.x-dev"
636 | }
637 | },
638 | "autoload": {
639 | "psr-4": {
640 | "Psr\\Log\\": "src"
641 | }
642 | },
643 | "notification-url": "https://packagist.org/downloads/",
644 | "license": [
645 | "MIT"
646 | ],
647 | "authors": [
648 | {
649 | "name": "PHP-FIG",
650 | "homepage": "https://www.php-fig.org/"
651 | }
652 | ],
653 | "description": "Common interface for logging libraries",
654 | "homepage": "https://github.com/php-fig/log",
655 | "keywords": [
656 | "log",
657 | "psr",
658 | "psr-3"
659 | ],
660 | "support": {
661 | "source": "https://github.com/php-fig/log/tree/3.0.2"
662 | },
663 | "time": "2024-09-11T13:17:53+00:00"
664 | },
665 | {
666 | "name": "react/cache",
667 | "version": "v1.2.0",
668 | "source": {
669 | "type": "git",
670 | "url": "https://github.com/reactphp/cache.git",
671 | "reference": "d47c472b64aa5608225f47965a484b75c7817d5b"
672 | },
673 | "dist": {
674 | "type": "zip",
675 | "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b",
676 | "reference": "d47c472b64aa5608225f47965a484b75c7817d5b",
677 | "shasum": ""
678 | },
679 | "require": {
680 | "php": ">=5.3.0",
681 | "react/promise": "^3.0 || ^2.0 || ^1.1"
682 | },
683 | "require-dev": {
684 | "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
685 | },
686 | "type": "library",
687 | "autoload": {
688 | "psr-4": {
689 | "React\\Cache\\": "src/"
690 | }
691 | },
692 | "notification-url": "https://packagist.org/downloads/",
693 | "license": [
694 | "MIT"
695 | ],
696 | "authors": [
697 | {
698 | "name": "Christian Lück",
699 | "email": "christian@clue.engineering",
700 | "homepage": "https://clue.engineering/"
701 | },
702 | {
703 | "name": "Cees-Jan Kiewiet",
704 | "email": "reactphp@ceesjankiewiet.nl",
705 | "homepage": "https://wyrihaximus.net/"
706 | },
707 | {
708 | "name": "Jan Sorgalla",
709 | "email": "jsorgalla@gmail.com",
710 | "homepage": "https://sorgalla.com/"
711 | },
712 | {
713 | "name": "Chris Boden",
714 | "email": "cboden@gmail.com",
715 | "homepage": "https://cboden.dev/"
716 | }
717 | ],
718 | "description": "Async, Promise-based cache interface for ReactPHP",
719 | "keywords": [
720 | "cache",
721 | "caching",
722 | "promise",
723 | "reactphp"
724 | ],
725 | "support": {
726 | "issues": "https://github.com/reactphp/cache/issues",
727 | "source": "https://github.com/reactphp/cache/tree/v1.2.0"
728 | },
729 | "funding": [
730 | {
731 | "url": "https://opencollective.com/reactphp",
732 | "type": "open_collective"
733 | }
734 | ],
735 | "time": "2022-11-30T15:59:55+00:00"
736 | },
737 | {
738 | "name": "react/child-process",
739 | "version": "v0.6.6",
740 | "source": {
741 | "type": "git",
742 | "url": "https://github.com/reactphp/child-process.git",
743 | "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159"
744 | },
745 | "dist": {
746 | "type": "zip",
747 | "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159",
748 | "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159",
749 | "shasum": ""
750 | },
751 | "require": {
752 | "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
753 | "php": ">=5.3.0",
754 | "react/event-loop": "^1.2",
755 | "react/stream": "^1.4"
756 | },
757 | "require-dev": {
758 | "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
759 | "react/socket": "^1.16",
760 | "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
761 | },
762 | "type": "library",
763 | "autoload": {
764 | "psr-4": {
765 | "React\\ChildProcess\\": "src/"
766 | }
767 | },
768 | "notification-url": "https://packagist.org/downloads/",
769 | "license": [
770 | "MIT"
771 | ],
772 | "authors": [
773 | {
774 | "name": "Christian Lück",
775 | "email": "christian@clue.engineering",
776 | "homepage": "https://clue.engineering/"
777 | },
778 | {
779 | "name": "Cees-Jan Kiewiet",
780 | "email": "reactphp@ceesjankiewiet.nl",
781 | "homepage": "https://wyrihaximus.net/"
782 | },
783 | {
784 | "name": "Jan Sorgalla",
785 | "email": "jsorgalla@gmail.com",
786 | "homepage": "https://sorgalla.com/"
787 | },
788 | {
789 | "name": "Chris Boden",
790 | "email": "cboden@gmail.com",
791 | "homepage": "https://cboden.dev/"
792 | }
793 | ],
794 | "description": "Event-driven library for executing child processes with ReactPHP.",
795 | "keywords": [
796 | "event-driven",
797 | "process",
798 | "reactphp"
799 | ],
800 | "support": {
801 | "issues": "https://github.com/reactphp/child-process/issues",
802 | "source": "https://github.com/reactphp/child-process/tree/v0.6.6"
803 | },
804 | "funding": [
805 | {
806 | "url": "https://opencollective.com/reactphp",
807 | "type": "open_collective"
808 | }
809 | ],
810 | "time": "2025-01-01T16:37:48+00:00"
811 | },
812 | {
813 | "name": "react/dns",
814 | "version": "v1.13.0",
815 | "source": {
816 | "type": "git",
817 | "url": "https://github.com/reactphp/dns.git",
818 | "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5"
819 | },
820 | "dist": {
821 | "type": "zip",
822 | "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5",
823 | "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5",
824 | "shasum": ""
825 | },
826 | "require": {
827 | "php": ">=5.3.0",
828 | "react/cache": "^1.0 || ^0.6 || ^0.5",
829 | "react/event-loop": "^1.2",
830 | "react/promise": "^3.2 || ^2.7 || ^1.2.1"
831 | },
832 | "require-dev": {
833 | "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
834 | "react/async": "^4.3 || ^3 || ^2",
835 | "react/promise-timer": "^1.11"
836 | },
837 | "type": "library",
838 | "autoload": {
839 | "psr-4": {
840 | "React\\Dns\\": "src/"
841 | }
842 | },
843 | "notification-url": "https://packagist.org/downloads/",
844 | "license": [
845 | "MIT"
846 | ],
847 | "authors": [
848 | {
849 | "name": "Christian Lück",
850 | "email": "christian@clue.engineering",
851 | "homepage": "https://clue.engineering/"
852 | },
853 | {
854 | "name": "Cees-Jan Kiewiet",
855 | "email": "reactphp@ceesjankiewiet.nl",
856 | "homepage": "https://wyrihaximus.net/"
857 | },
858 | {
859 | "name": "Jan Sorgalla",
860 | "email": "jsorgalla@gmail.com",
861 | "homepage": "https://sorgalla.com/"
862 | },
863 | {
864 | "name": "Chris Boden",
865 | "email": "cboden@gmail.com",
866 | "homepage": "https://cboden.dev/"
867 | }
868 | ],
869 | "description": "Async DNS resolver for ReactPHP",
870 | "keywords": [
871 | "async",
872 | "dns",
873 | "dns-resolver",
874 | "reactphp"
875 | ],
876 | "support": {
877 | "issues": "https://github.com/reactphp/dns/issues",
878 | "source": "https://github.com/reactphp/dns/tree/v1.13.0"
879 | },
880 | "funding": [
881 | {
882 | "url": "https://opencollective.com/reactphp",
883 | "type": "open_collective"
884 | }
885 | ],
886 | "time": "2024-06-13T14:18:03+00:00"
887 | },
888 | {
889 | "name": "react/event-loop",
890 | "version": "v1.5.0",
891 | "source": {
892 | "type": "git",
893 | "url": "https://github.com/reactphp/event-loop.git",
894 | "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354"
895 | },
896 | "dist": {
897 | "type": "zip",
898 | "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354",
899 | "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354",
900 | "shasum": ""
901 | },
902 | "require": {
903 | "php": ">=5.3.0"
904 | },
905 | "require-dev": {
906 | "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
907 | },
908 | "suggest": {
909 | "ext-pcntl": "For signal handling support when using the StreamSelectLoop"
910 | },
911 | "type": "library",
912 | "autoload": {
913 | "psr-4": {
914 | "React\\EventLoop\\": "src/"
915 | }
916 | },
917 | "notification-url": "https://packagist.org/downloads/",
918 | "license": [
919 | "MIT"
920 | ],
921 | "authors": [
922 | {
923 | "name": "Christian Lück",
924 | "email": "christian@clue.engineering",
925 | "homepage": "https://clue.engineering/"
926 | },
927 | {
928 | "name": "Cees-Jan Kiewiet",
929 | "email": "reactphp@ceesjankiewiet.nl",
930 | "homepage": "https://wyrihaximus.net/"
931 | },
932 | {
933 | "name": "Jan Sorgalla",
934 | "email": "jsorgalla@gmail.com",
935 | "homepage": "https://sorgalla.com/"
936 | },
937 | {
938 | "name": "Chris Boden",
939 | "email": "cboden@gmail.com",
940 | "homepage": "https://cboden.dev/"
941 | }
942 | ],
943 | "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
944 | "keywords": [
945 | "asynchronous",
946 | "event-loop"
947 | ],
948 | "support": {
949 | "issues": "https://github.com/reactphp/event-loop/issues",
950 | "source": "https://github.com/reactphp/event-loop/tree/v1.5.0"
951 | },
952 | "funding": [
953 | {
954 | "url": "https://opencollective.com/reactphp",
955 | "type": "open_collective"
956 | }
957 | ],
958 | "time": "2023-11-13T13:48:05+00:00"
959 | },
960 | {
961 | "name": "react/promise",
962 | "version": "v3.2.0",
963 | "source": {
964 | "type": "git",
965 | "url": "https://github.com/reactphp/promise.git",
966 | "reference": "8a164643313c71354582dc850b42b33fa12a4b63"
967 | },
968 | "dist": {
969 | "type": "zip",
970 | "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63",
971 | "reference": "8a164643313c71354582dc850b42b33fa12a4b63",
972 | "shasum": ""
973 | },
974 | "require": {
975 | "php": ">=7.1.0"
976 | },
977 | "require-dev": {
978 | "phpstan/phpstan": "1.10.39 || 1.4.10",
979 | "phpunit/phpunit": "^9.6 || ^7.5"
980 | },
981 | "type": "library",
982 | "autoload": {
983 | "files": [
984 | "src/functions_include.php"
985 | ],
986 | "psr-4": {
987 | "React\\Promise\\": "src/"
988 | }
989 | },
990 | "notification-url": "https://packagist.org/downloads/",
991 | "license": [
992 | "MIT"
993 | ],
994 | "authors": [
995 | {
996 | "name": "Jan Sorgalla",
997 | "email": "jsorgalla@gmail.com",
998 | "homepage": "https://sorgalla.com/"
999 | },
1000 | {
1001 | "name": "Christian Lück",
1002 | "email": "christian@clue.engineering",
1003 | "homepage": "https://clue.engineering/"
1004 | },
1005 | {
1006 | "name": "Cees-Jan Kiewiet",
1007 | "email": "reactphp@ceesjankiewiet.nl",
1008 | "homepage": "https://wyrihaximus.net/"
1009 | },
1010 | {
1011 | "name": "Chris Boden",
1012 | "email": "cboden@gmail.com",
1013 | "homepage": "https://cboden.dev/"
1014 | }
1015 | ],
1016 | "description": "A lightweight implementation of CommonJS Promises/A for PHP",
1017 | "keywords": [
1018 | "promise",
1019 | "promises"
1020 | ],
1021 | "support": {
1022 | "issues": "https://github.com/reactphp/promise/issues",
1023 | "source": "https://github.com/reactphp/promise/tree/v3.2.0"
1024 | },
1025 | "funding": [
1026 | {
1027 | "url": "https://opencollective.com/reactphp",
1028 | "type": "open_collective"
1029 | }
1030 | ],
1031 | "time": "2024-05-24T10:39:05+00:00"
1032 | },
1033 | {
1034 | "name": "react/socket",
1035 | "version": "v1.16.0",
1036 | "source": {
1037 | "type": "git",
1038 | "url": "https://github.com/reactphp/socket.git",
1039 | "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1"
1040 | },
1041 | "dist": {
1042 | "type": "zip",
1043 | "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1",
1044 | "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1",
1045 | "shasum": ""
1046 | },
1047 | "require": {
1048 | "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
1049 | "php": ">=5.3.0",
1050 | "react/dns": "^1.13",
1051 | "react/event-loop": "^1.2",
1052 | "react/promise": "^3.2 || ^2.6 || ^1.2.1",
1053 | "react/stream": "^1.4"
1054 | },
1055 | "require-dev": {
1056 | "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
1057 | "react/async": "^4.3 || ^3.3 || ^2",
1058 | "react/promise-stream": "^1.4",
1059 | "react/promise-timer": "^1.11"
1060 | },
1061 | "type": "library",
1062 | "autoload": {
1063 | "psr-4": {
1064 | "React\\Socket\\": "src/"
1065 | }
1066 | },
1067 | "notification-url": "https://packagist.org/downloads/",
1068 | "license": [
1069 | "MIT"
1070 | ],
1071 | "authors": [
1072 | {
1073 | "name": "Christian Lück",
1074 | "email": "christian@clue.engineering",
1075 | "homepage": "https://clue.engineering/"
1076 | },
1077 | {
1078 | "name": "Cees-Jan Kiewiet",
1079 | "email": "reactphp@ceesjankiewiet.nl",
1080 | "homepage": "https://wyrihaximus.net/"
1081 | },
1082 | {
1083 | "name": "Jan Sorgalla",
1084 | "email": "jsorgalla@gmail.com",
1085 | "homepage": "https://sorgalla.com/"
1086 | },
1087 | {
1088 | "name": "Chris Boden",
1089 | "email": "cboden@gmail.com",
1090 | "homepage": "https://cboden.dev/"
1091 | }
1092 | ],
1093 | "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
1094 | "keywords": [
1095 | "Connection",
1096 | "Socket",
1097 | "async",
1098 | "reactphp",
1099 | "stream"
1100 | ],
1101 | "support": {
1102 | "issues": "https://github.com/reactphp/socket/issues",
1103 | "source": "https://github.com/reactphp/socket/tree/v1.16.0"
1104 | },
1105 | "funding": [
1106 | {
1107 | "url": "https://opencollective.com/reactphp",
1108 | "type": "open_collective"
1109 | }
1110 | ],
1111 | "time": "2024-07-26T10:38:09+00:00"
1112 | },
1113 | {
1114 | "name": "react/stream",
1115 | "version": "v1.4.0",
1116 | "source": {
1117 | "type": "git",
1118 | "url": "https://github.com/reactphp/stream.git",
1119 | "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d"
1120 | },
1121 | "dist": {
1122 | "type": "zip",
1123 | "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d",
1124 | "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d",
1125 | "shasum": ""
1126 | },
1127 | "require": {
1128 | "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
1129 | "php": ">=5.3.8",
1130 | "react/event-loop": "^1.2"
1131 | },
1132 | "require-dev": {
1133 | "clue/stream-filter": "~1.2",
1134 | "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
1135 | },
1136 | "type": "library",
1137 | "autoload": {
1138 | "psr-4": {
1139 | "React\\Stream\\": "src/"
1140 | }
1141 | },
1142 | "notification-url": "https://packagist.org/downloads/",
1143 | "license": [
1144 | "MIT"
1145 | ],
1146 | "authors": [
1147 | {
1148 | "name": "Christian Lück",
1149 | "email": "christian@clue.engineering",
1150 | "homepage": "https://clue.engineering/"
1151 | },
1152 | {
1153 | "name": "Cees-Jan Kiewiet",
1154 | "email": "reactphp@ceesjankiewiet.nl",
1155 | "homepage": "https://wyrihaximus.net/"
1156 | },
1157 | {
1158 | "name": "Jan Sorgalla",
1159 | "email": "jsorgalla@gmail.com",
1160 | "homepage": "https://sorgalla.com/"
1161 | },
1162 | {
1163 | "name": "Chris Boden",
1164 | "email": "cboden@gmail.com",
1165 | "homepage": "https://cboden.dev/"
1166 | }
1167 | ],
1168 | "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
1169 | "keywords": [
1170 | "event-driven",
1171 | "io",
1172 | "non-blocking",
1173 | "pipe",
1174 | "reactphp",
1175 | "readable",
1176 | "stream",
1177 | "writable"
1178 | ],
1179 | "support": {
1180 | "issues": "https://github.com/reactphp/stream/issues",
1181 | "source": "https://github.com/reactphp/stream/tree/v1.4.0"
1182 | },
1183 | "funding": [
1184 | {
1185 | "url": "https://opencollective.com/reactphp",
1186 | "type": "open_collective"
1187 | }
1188 | ],
1189 | "time": "2024-06-11T12:45:25+00:00"
1190 | },
1191 | {
1192 | "name": "sebastian/diff",
1193 | "version": "7.0.0",
1194 | "source": {
1195 | "type": "git",
1196 | "url": "https://github.com/sebastianbergmann/diff.git",
1197 | "reference": "7ab1ea946c012266ca32390913653d844ecd085f"
1198 | },
1199 | "dist": {
1200 | "type": "zip",
1201 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
1202 | "reference": "7ab1ea946c012266ca32390913653d844ecd085f",
1203 | "shasum": ""
1204 | },
1205 | "require": {
1206 | "php": ">=8.3"
1207 | },
1208 | "require-dev": {
1209 | "phpunit/phpunit": "^12.0",
1210 | "symfony/process": "^7.2"
1211 | },
1212 | "type": "library",
1213 | "extra": {
1214 | "branch-alias": {
1215 | "dev-main": "7.0-dev"
1216 | }
1217 | },
1218 | "autoload": {
1219 | "classmap": [
1220 | "src/"
1221 | ]
1222 | },
1223 | "notification-url": "https://packagist.org/downloads/",
1224 | "license": [
1225 | "BSD-3-Clause"
1226 | ],
1227 | "authors": [
1228 | {
1229 | "name": "Sebastian Bergmann",
1230 | "email": "sebastian@phpunit.de"
1231 | },
1232 | {
1233 | "name": "Kore Nordmann",
1234 | "email": "mail@kore-nordmann.de"
1235 | }
1236 | ],
1237 | "description": "Diff implementation",
1238 | "homepage": "https://github.com/sebastianbergmann/diff",
1239 | "keywords": [
1240 | "diff",
1241 | "udiff",
1242 | "unidiff",
1243 | "unified diff"
1244 | ],
1245 | "support": {
1246 | "issues": "https://github.com/sebastianbergmann/diff/issues",
1247 | "security": "https://github.com/sebastianbergmann/diff/security/policy",
1248 | "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
1249 | },
1250 | "funding": [
1251 | {
1252 | "url": "https://github.com/sebastianbergmann",
1253 | "type": "github"
1254 | }
1255 | ],
1256 | "time": "2025-02-07T04:55:46+00:00"
1257 | },
1258 | {
1259 | "name": "symfony/console",
1260 | "version": "v7.3.2",
1261 | "source": {
1262 | "type": "git",
1263 | "url": "https://github.com/symfony/console.git",
1264 | "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1"
1265 | },
1266 | "dist": {
1267 | "type": "zip",
1268 | "url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1",
1269 | "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1",
1270 | "shasum": ""
1271 | },
1272 | "require": {
1273 | "php": ">=8.2",
1274 | "symfony/deprecation-contracts": "^2.5|^3",
1275 | "symfony/polyfill-mbstring": "~1.0",
1276 | "symfony/service-contracts": "^2.5|^3",
1277 | "symfony/string": "^7.2"
1278 | },
1279 | "conflict": {
1280 | "symfony/dependency-injection": "<6.4",
1281 | "symfony/dotenv": "<6.4",
1282 | "symfony/event-dispatcher": "<6.4",
1283 | "symfony/lock": "<6.4",
1284 | "symfony/process": "<6.4"
1285 | },
1286 | "provide": {
1287 | "psr/log-implementation": "1.0|2.0|3.0"
1288 | },
1289 | "require-dev": {
1290 | "psr/log": "^1|^2|^3",
1291 | "symfony/config": "^6.4|^7.0",
1292 | "symfony/dependency-injection": "^6.4|^7.0",
1293 | "symfony/event-dispatcher": "^6.4|^7.0",
1294 | "symfony/http-foundation": "^6.4|^7.0",
1295 | "symfony/http-kernel": "^6.4|^7.0",
1296 | "symfony/lock": "^6.4|^7.0",
1297 | "symfony/messenger": "^6.4|^7.0",
1298 | "symfony/process": "^6.4|^7.0",
1299 | "symfony/stopwatch": "^6.4|^7.0",
1300 | "symfony/var-dumper": "^6.4|^7.0"
1301 | },
1302 | "type": "library",
1303 | "autoload": {
1304 | "psr-4": {
1305 | "Symfony\\Component\\Console\\": ""
1306 | },
1307 | "exclude-from-classmap": [
1308 | "/Tests/"
1309 | ]
1310 | },
1311 | "notification-url": "https://packagist.org/downloads/",
1312 | "license": [
1313 | "MIT"
1314 | ],
1315 | "authors": [
1316 | {
1317 | "name": "Fabien Potencier",
1318 | "email": "fabien@symfony.com"
1319 | },
1320 | {
1321 | "name": "Symfony Community",
1322 | "homepage": "https://symfony.com/contributors"
1323 | }
1324 | ],
1325 | "description": "Eases the creation of beautiful and testable command line interfaces",
1326 | "homepage": "https://symfony.com",
1327 | "keywords": [
1328 | "cli",
1329 | "command-line",
1330 | "console",
1331 | "terminal"
1332 | ],
1333 | "support": {
1334 | "source": "https://github.com/symfony/console/tree/v7.3.2"
1335 | },
1336 | "funding": [
1337 | {
1338 | "url": "https://symfony.com/sponsor",
1339 | "type": "custom"
1340 | },
1341 | {
1342 | "url": "https://github.com/fabpot",
1343 | "type": "github"
1344 | },
1345 | {
1346 | "url": "https://github.com/nicolas-grekas",
1347 | "type": "github"
1348 | },
1349 | {
1350 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1351 | "type": "tidelift"
1352 | }
1353 | ],
1354 | "time": "2025-07-30T17:13:41+00:00"
1355 | },
1356 | {
1357 | "name": "symfony/deprecation-contracts",
1358 | "version": "v3.6.0",
1359 | "source": {
1360 | "type": "git",
1361 | "url": "https://github.com/symfony/deprecation-contracts.git",
1362 | "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
1363 | },
1364 | "dist": {
1365 | "type": "zip",
1366 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
1367 | "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
1368 | "shasum": ""
1369 | },
1370 | "require": {
1371 | "php": ">=8.1"
1372 | },
1373 | "type": "library",
1374 | "extra": {
1375 | "thanks": {
1376 | "url": "https://github.com/symfony/contracts",
1377 | "name": "symfony/contracts"
1378 | },
1379 | "branch-alias": {
1380 | "dev-main": "3.6-dev"
1381 | }
1382 | },
1383 | "autoload": {
1384 | "files": [
1385 | "function.php"
1386 | ]
1387 | },
1388 | "notification-url": "https://packagist.org/downloads/",
1389 | "license": [
1390 | "MIT"
1391 | ],
1392 | "authors": [
1393 | {
1394 | "name": "Nicolas Grekas",
1395 | "email": "p@tchwork.com"
1396 | },
1397 | {
1398 | "name": "Symfony Community",
1399 | "homepage": "https://symfony.com/contributors"
1400 | }
1401 | ],
1402 | "description": "A generic function and convention to trigger deprecation notices",
1403 | "homepage": "https://symfony.com",
1404 | "support": {
1405 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
1406 | },
1407 | "funding": [
1408 | {
1409 | "url": "https://symfony.com/sponsor",
1410 | "type": "custom"
1411 | },
1412 | {
1413 | "url": "https://github.com/fabpot",
1414 | "type": "github"
1415 | },
1416 | {
1417 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1418 | "type": "tidelift"
1419 | }
1420 | ],
1421 | "time": "2024-09-25T14:21:43+00:00"
1422 | },
1423 | {
1424 | "name": "symfony/event-dispatcher",
1425 | "version": "v7.3.0",
1426 | "source": {
1427 | "type": "git",
1428 | "url": "https://github.com/symfony/event-dispatcher.git",
1429 | "reference": "497f73ac996a598c92409b44ac43b6690c4f666d"
1430 | },
1431 | "dist": {
1432 | "type": "zip",
1433 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d",
1434 | "reference": "497f73ac996a598c92409b44ac43b6690c4f666d",
1435 | "shasum": ""
1436 | },
1437 | "require": {
1438 | "php": ">=8.2",
1439 | "symfony/event-dispatcher-contracts": "^2.5|^3"
1440 | },
1441 | "conflict": {
1442 | "symfony/dependency-injection": "<6.4",
1443 | "symfony/service-contracts": "<2.5"
1444 | },
1445 | "provide": {
1446 | "psr/event-dispatcher-implementation": "1.0",
1447 | "symfony/event-dispatcher-implementation": "2.0|3.0"
1448 | },
1449 | "require-dev": {
1450 | "psr/log": "^1|^2|^3",
1451 | "symfony/config": "^6.4|^7.0",
1452 | "symfony/dependency-injection": "^6.4|^7.0",
1453 | "symfony/error-handler": "^6.4|^7.0",
1454 | "symfony/expression-language": "^6.4|^7.0",
1455 | "symfony/http-foundation": "^6.4|^7.0",
1456 | "symfony/service-contracts": "^2.5|^3",
1457 | "symfony/stopwatch": "^6.4|^7.0"
1458 | },
1459 | "type": "library",
1460 | "autoload": {
1461 | "psr-4": {
1462 | "Symfony\\Component\\EventDispatcher\\": ""
1463 | },
1464 | "exclude-from-classmap": [
1465 | "/Tests/"
1466 | ]
1467 | },
1468 | "notification-url": "https://packagist.org/downloads/",
1469 | "license": [
1470 | "MIT"
1471 | ],
1472 | "authors": [
1473 | {
1474 | "name": "Fabien Potencier",
1475 | "email": "fabien@symfony.com"
1476 | },
1477 | {
1478 | "name": "Symfony Community",
1479 | "homepage": "https://symfony.com/contributors"
1480 | }
1481 | ],
1482 | "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
1483 | "homepage": "https://symfony.com",
1484 | "support": {
1485 | "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0"
1486 | },
1487 | "funding": [
1488 | {
1489 | "url": "https://symfony.com/sponsor",
1490 | "type": "custom"
1491 | },
1492 | {
1493 | "url": "https://github.com/fabpot",
1494 | "type": "github"
1495 | },
1496 | {
1497 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1498 | "type": "tidelift"
1499 | }
1500 | ],
1501 | "time": "2025-04-22T09:11:45+00:00"
1502 | },
1503 | {
1504 | "name": "symfony/event-dispatcher-contracts",
1505 | "version": "v3.6.0",
1506 | "source": {
1507 | "type": "git",
1508 | "url": "https://github.com/symfony/event-dispatcher-contracts.git",
1509 | "reference": "59eb412e93815df44f05f342958efa9f46b1e586"
1510 | },
1511 | "dist": {
1512 | "type": "zip",
1513 | "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
1514 | "reference": "59eb412e93815df44f05f342958efa9f46b1e586",
1515 | "shasum": ""
1516 | },
1517 | "require": {
1518 | "php": ">=8.1",
1519 | "psr/event-dispatcher": "^1"
1520 | },
1521 | "type": "library",
1522 | "extra": {
1523 | "thanks": {
1524 | "url": "https://github.com/symfony/contracts",
1525 | "name": "symfony/contracts"
1526 | },
1527 | "branch-alias": {
1528 | "dev-main": "3.6-dev"
1529 | }
1530 | },
1531 | "autoload": {
1532 | "psr-4": {
1533 | "Symfony\\Contracts\\EventDispatcher\\": ""
1534 | }
1535 | },
1536 | "notification-url": "https://packagist.org/downloads/",
1537 | "license": [
1538 | "MIT"
1539 | ],
1540 | "authors": [
1541 | {
1542 | "name": "Nicolas Grekas",
1543 | "email": "p@tchwork.com"
1544 | },
1545 | {
1546 | "name": "Symfony Community",
1547 | "homepage": "https://symfony.com/contributors"
1548 | }
1549 | ],
1550 | "description": "Generic abstractions related to dispatching event",
1551 | "homepage": "https://symfony.com",
1552 | "keywords": [
1553 | "abstractions",
1554 | "contracts",
1555 | "decoupling",
1556 | "interfaces",
1557 | "interoperability",
1558 | "standards"
1559 | ],
1560 | "support": {
1561 | "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0"
1562 | },
1563 | "funding": [
1564 | {
1565 | "url": "https://symfony.com/sponsor",
1566 | "type": "custom"
1567 | },
1568 | {
1569 | "url": "https://github.com/fabpot",
1570 | "type": "github"
1571 | },
1572 | {
1573 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1574 | "type": "tidelift"
1575 | }
1576 | ],
1577 | "time": "2024-09-25T14:21:43+00:00"
1578 | },
1579 | {
1580 | "name": "symfony/filesystem",
1581 | "version": "v7.3.2",
1582 | "source": {
1583 | "type": "git",
1584 | "url": "https://github.com/symfony/filesystem.git",
1585 | "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd"
1586 | },
1587 | "dist": {
1588 | "type": "zip",
1589 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd",
1590 | "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd",
1591 | "shasum": ""
1592 | },
1593 | "require": {
1594 | "php": ">=8.2",
1595 | "symfony/polyfill-ctype": "~1.8",
1596 | "symfony/polyfill-mbstring": "~1.8"
1597 | },
1598 | "require-dev": {
1599 | "symfony/process": "^6.4|^7.0"
1600 | },
1601 | "type": "library",
1602 | "autoload": {
1603 | "psr-4": {
1604 | "Symfony\\Component\\Filesystem\\": ""
1605 | },
1606 | "exclude-from-classmap": [
1607 | "/Tests/"
1608 | ]
1609 | },
1610 | "notification-url": "https://packagist.org/downloads/",
1611 | "license": [
1612 | "MIT"
1613 | ],
1614 | "authors": [
1615 | {
1616 | "name": "Fabien Potencier",
1617 | "email": "fabien@symfony.com"
1618 | },
1619 | {
1620 | "name": "Symfony Community",
1621 | "homepage": "https://symfony.com/contributors"
1622 | }
1623 | ],
1624 | "description": "Provides basic utilities for the filesystem",
1625 | "homepage": "https://symfony.com",
1626 | "support": {
1627 | "source": "https://github.com/symfony/filesystem/tree/v7.3.2"
1628 | },
1629 | "funding": [
1630 | {
1631 | "url": "https://symfony.com/sponsor",
1632 | "type": "custom"
1633 | },
1634 | {
1635 | "url": "https://github.com/fabpot",
1636 | "type": "github"
1637 | },
1638 | {
1639 | "url": "https://github.com/nicolas-grekas",
1640 | "type": "github"
1641 | },
1642 | {
1643 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1644 | "type": "tidelift"
1645 | }
1646 | ],
1647 | "time": "2025-07-07T08:17:47+00:00"
1648 | },
1649 | {
1650 | "name": "symfony/finder",
1651 | "version": "v7.3.2",
1652 | "source": {
1653 | "type": "git",
1654 | "url": "https://github.com/symfony/finder.git",
1655 | "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
1656 | },
1657 | "dist": {
1658 | "type": "zip",
1659 | "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
1660 | "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
1661 | "shasum": ""
1662 | },
1663 | "require": {
1664 | "php": ">=8.2"
1665 | },
1666 | "require-dev": {
1667 | "symfony/filesystem": "^6.4|^7.0"
1668 | },
1669 | "type": "library",
1670 | "autoload": {
1671 | "psr-4": {
1672 | "Symfony\\Component\\Finder\\": ""
1673 | },
1674 | "exclude-from-classmap": [
1675 | "/Tests/"
1676 | ]
1677 | },
1678 | "notification-url": "https://packagist.org/downloads/",
1679 | "license": [
1680 | "MIT"
1681 | ],
1682 | "authors": [
1683 | {
1684 | "name": "Fabien Potencier",
1685 | "email": "fabien@symfony.com"
1686 | },
1687 | {
1688 | "name": "Symfony Community",
1689 | "homepage": "https://symfony.com/contributors"
1690 | }
1691 | ],
1692 | "description": "Finds files and directories via an intuitive fluent interface",
1693 | "homepage": "https://symfony.com",
1694 | "support": {
1695 | "source": "https://github.com/symfony/finder/tree/v7.3.2"
1696 | },
1697 | "funding": [
1698 | {
1699 | "url": "https://symfony.com/sponsor",
1700 | "type": "custom"
1701 | },
1702 | {
1703 | "url": "https://github.com/fabpot",
1704 | "type": "github"
1705 | },
1706 | {
1707 | "url": "https://github.com/nicolas-grekas",
1708 | "type": "github"
1709 | },
1710 | {
1711 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1712 | "type": "tidelift"
1713 | }
1714 | ],
1715 | "time": "2025-07-15T13:41:35+00:00"
1716 | },
1717 | {
1718 | "name": "symfony/options-resolver",
1719 | "version": "v7.3.2",
1720 | "source": {
1721 | "type": "git",
1722 | "url": "https://github.com/symfony/options-resolver.git",
1723 | "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37"
1724 | },
1725 | "dist": {
1726 | "type": "zip",
1727 | "url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37",
1728 | "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37",
1729 | "shasum": ""
1730 | },
1731 | "require": {
1732 | "php": ">=8.2",
1733 | "symfony/deprecation-contracts": "^2.5|^3"
1734 | },
1735 | "type": "library",
1736 | "autoload": {
1737 | "psr-4": {
1738 | "Symfony\\Component\\OptionsResolver\\": ""
1739 | },
1740 | "exclude-from-classmap": [
1741 | "/Tests/"
1742 | ]
1743 | },
1744 | "notification-url": "https://packagist.org/downloads/",
1745 | "license": [
1746 | "MIT"
1747 | ],
1748 | "authors": [
1749 | {
1750 | "name": "Fabien Potencier",
1751 | "email": "fabien@symfony.com"
1752 | },
1753 | {
1754 | "name": "Symfony Community",
1755 | "homepage": "https://symfony.com/contributors"
1756 | }
1757 | ],
1758 | "description": "Provides an improved replacement for the array_replace PHP function",
1759 | "homepage": "https://symfony.com",
1760 | "keywords": [
1761 | "config",
1762 | "configuration",
1763 | "options"
1764 | ],
1765 | "support": {
1766 | "source": "https://github.com/symfony/options-resolver/tree/v7.3.2"
1767 | },
1768 | "funding": [
1769 | {
1770 | "url": "https://symfony.com/sponsor",
1771 | "type": "custom"
1772 | },
1773 | {
1774 | "url": "https://github.com/fabpot",
1775 | "type": "github"
1776 | },
1777 | {
1778 | "url": "https://github.com/nicolas-grekas",
1779 | "type": "github"
1780 | },
1781 | {
1782 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1783 | "type": "tidelift"
1784 | }
1785 | ],
1786 | "time": "2025-07-15T11:36:08+00:00"
1787 | },
1788 | {
1789 | "name": "symfony/polyfill-ctype",
1790 | "version": "v1.32.0",
1791 | "source": {
1792 | "type": "git",
1793 | "url": "https://github.com/symfony/polyfill-ctype.git",
1794 | "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
1795 | },
1796 | "dist": {
1797 | "type": "zip",
1798 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
1799 | "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
1800 | "shasum": ""
1801 | },
1802 | "require": {
1803 | "php": ">=7.2"
1804 | },
1805 | "provide": {
1806 | "ext-ctype": "*"
1807 | },
1808 | "suggest": {
1809 | "ext-ctype": "For best performance"
1810 | },
1811 | "type": "library",
1812 | "extra": {
1813 | "thanks": {
1814 | "url": "https://github.com/symfony/polyfill",
1815 | "name": "symfony/polyfill"
1816 | }
1817 | },
1818 | "autoload": {
1819 | "files": [
1820 | "bootstrap.php"
1821 | ],
1822 | "psr-4": {
1823 | "Symfony\\Polyfill\\Ctype\\": ""
1824 | }
1825 | },
1826 | "notification-url": "https://packagist.org/downloads/",
1827 | "license": [
1828 | "MIT"
1829 | ],
1830 | "authors": [
1831 | {
1832 | "name": "Gert de Pagter",
1833 | "email": "BackEndTea@gmail.com"
1834 | },
1835 | {
1836 | "name": "Symfony Community",
1837 | "homepage": "https://symfony.com/contributors"
1838 | }
1839 | ],
1840 | "description": "Symfony polyfill for ctype functions",
1841 | "homepage": "https://symfony.com",
1842 | "keywords": [
1843 | "compatibility",
1844 | "ctype",
1845 | "polyfill",
1846 | "portable"
1847 | ],
1848 | "support": {
1849 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
1850 | },
1851 | "funding": [
1852 | {
1853 | "url": "https://symfony.com/sponsor",
1854 | "type": "custom"
1855 | },
1856 | {
1857 | "url": "https://github.com/fabpot",
1858 | "type": "github"
1859 | },
1860 | {
1861 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1862 | "type": "tidelift"
1863 | }
1864 | ],
1865 | "time": "2024-09-09T11:45:10+00:00"
1866 | },
1867 | {
1868 | "name": "symfony/polyfill-intl-grapheme",
1869 | "version": "v1.32.0",
1870 | "source": {
1871 | "type": "git",
1872 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
1873 | "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
1874 | },
1875 | "dist": {
1876 | "type": "zip",
1877 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
1878 | "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
1879 | "shasum": ""
1880 | },
1881 | "require": {
1882 | "php": ">=7.2"
1883 | },
1884 | "suggest": {
1885 | "ext-intl": "For best performance"
1886 | },
1887 | "type": "library",
1888 | "extra": {
1889 | "thanks": {
1890 | "url": "https://github.com/symfony/polyfill",
1891 | "name": "symfony/polyfill"
1892 | }
1893 | },
1894 | "autoload": {
1895 | "files": [
1896 | "bootstrap.php"
1897 | ],
1898 | "psr-4": {
1899 | "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
1900 | }
1901 | },
1902 | "notification-url": "https://packagist.org/downloads/",
1903 | "license": [
1904 | "MIT"
1905 | ],
1906 | "authors": [
1907 | {
1908 | "name": "Nicolas Grekas",
1909 | "email": "p@tchwork.com"
1910 | },
1911 | {
1912 | "name": "Symfony Community",
1913 | "homepage": "https://symfony.com/contributors"
1914 | }
1915 | ],
1916 | "description": "Symfony polyfill for intl's grapheme_* functions",
1917 | "homepage": "https://symfony.com",
1918 | "keywords": [
1919 | "compatibility",
1920 | "grapheme",
1921 | "intl",
1922 | "polyfill",
1923 | "portable",
1924 | "shim"
1925 | ],
1926 | "support": {
1927 | "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
1928 | },
1929 | "funding": [
1930 | {
1931 | "url": "https://symfony.com/sponsor",
1932 | "type": "custom"
1933 | },
1934 | {
1935 | "url": "https://github.com/fabpot",
1936 | "type": "github"
1937 | },
1938 | {
1939 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1940 | "type": "tidelift"
1941 | }
1942 | ],
1943 | "time": "2024-09-09T11:45:10+00:00"
1944 | },
1945 | {
1946 | "name": "symfony/polyfill-intl-normalizer",
1947 | "version": "v1.32.0",
1948 | "source": {
1949 | "type": "git",
1950 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
1951 | "reference": "3833d7255cc303546435cb650316bff708a1c75c"
1952 | },
1953 | "dist": {
1954 | "type": "zip",
1955 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
1956 | "reference": "3833d7255cc303546435cb650316bff708a1c75c",
1957 | "shasum": ""
1958 | },
1959 | "require": {
1960 | "php": ">=7.2"
1961 | },
1962 | "suggest": {
1963 | "ext-intl": "For best performance"
1964 | },
1965 | "type": "library",
1966 | "extra": {
1967 | "thanks": {
1968 | "url": "https://github.com/symfony/polyfill",
1969 | "name": "symfony/polyfill"
1970 | }
1971 | },
1972 | "autoload": {
1973 | "files": [
1974 | "bootstrap.php"
1975 | ],
1976 | "psr-4": {
1977 | "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
1978 | },
1979 | "classmap": [
1980 | "Resources/stubs"
1981 | ]
1982 | },
1983 | "notification-url": "https://packagist.org/downloads/",
1984 | "license": [
1985 | "MIT"
1986 | ],
1987 | "authors": [
1988 | {
1989 | "name": "Nicolas Grekas",
1990 | "email": "p@tchwork.com"
1991 | },
1992 | {
1993 | "name": "Symfony Community",
1994 | "homepage": "https://symfony.com/contributors"
1995 | }
1996 | ],
1997 | "description": "Symfony polyfill for intl's Normalizer class and related functions",
1998 | "homepage": "https://symfony.com",
1999 | "keywords": [
2000 | "compatibility",
2001 | "intl",
2002 | "normalizer",
2003 | "polyfill",
2004 | "portable",
2005 | "shim"
2006 | ],
2007 | "support": {
2008 | "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
2009 | },
2010 | "funding": [
2011 | {
2012 | "url": "https://symfony.com/sponsor",
2013 | "type": "custom"
2014 | },
2015 | {
2016 | "url": "https://github.com/fabpot",
2017 | "type": "github"
2018 | },
2019 | {
2020 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2021 | "type": "tidelift"
2022 | }
2023 | ],
2024 | "time": "2024-09-09T11:45:10+00:00"
2025 | },
2026 | {
2027 | "name": "symfony/polyfill-mbstring",
2028 | "version": "v1.32.0",
2029 | "source": {
2030 | "type": "git",
2031 | "url": "https://github.com/symfony/polyfill-mbstring.git",
2032 | "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
2033 | },
2034 | "dist": {
2035 | "type": "zip",
2036 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
2037 | "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
2038 | "shasum": ""
2039 | },
2040 | "require": {
2041 | "ext-iconv": "*",
2042 | "php": ">=7.2"
2043 | },
2044 | "provide": {
2045 | "ext-mbstring": "*"
2046 | },
2047 | "suggest": {
2048 | "ext-mbstring": "For best performance"
2049 | },
2050 | "type": "library",
2051 | "extra": {
2052 | "thanks": {
2053 | "url": "https://github.com/symfony/polyfill",
2054 | "name": "symfony/polyfill"
2055 | }
2056 | },
2057 | "autoload": {
2058 | "files": [
2059 | "bootstrap.php"
2060 | ],
2061 | "psr-4": {
2062 | "Symfony\\Polyfill\\Mbstring\\": ""
2063 | }
2064 | },
2065 | "notification-url": "https://packagist.org/downloads/",
2066 | "license": [
2067 | "MIT"
2068 | ],
2069 | "authors": [
2070 | {
2071 | "name": "Nicolas Grekas",
2072 | "email": "p@tchwork.com"
2073 | },
2074 | {
2075 | "name": "Symfony Community",
2076 | "homepage": "https://symfony.com/contributors"
2077 | }
2078 | ],
2079 | "description": "Symfony polyfill for the Mbstring extension",
2080 | "homepage": "https://symfony.com",
2081 | "keywords": [
2082 | "compatibility",
2083 | "mbstring",
2084 | "polyfill",
2085 | "portable",
2086 | "shim"
2087 | ],
2088 | "support": {
2089 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
2090 | },
2091 | "funding": [
2092 | {
2093 | "url": "https://symfony.com/sponsor",
2094 | "type": "custom"
2095 | },
2096 | {
2097 | "url": "https://github.com/fabpot",
2098 | "type": "github"
2099 | },
2100 | {
2101 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2102 | "type": "tidelift"
2103 | }
2104 | ],
2105 | "time": "2024-12-23T08:48:59+00:00"
2106 | },
2107 | {
2108 | "name": "symfony/polyfill-php80",
2109 | "version": "v1.32.0",
2110 | "source": {
2111 | "type": "git",
2112 | "url": "https://github.com/symfony/polyfill-php80.git",
2113 | "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
2114 | },
2115 | "dist": {
2116 | "type": "zip",
2117 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
2118 | "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
2119 | "shasum": ""
2120 | },
2121 | "require": {
2122 | "php": ">=7.2"
2123 | },
2124 | "type": "library",
2125 | "extra": {
2126 | "thanks": {
2127 | "url": "https://github.com/symfony/polyfill",
2128 | "name": "symfony/polyfill"
2129 | }
2130 | },
2131 | "autoload": {
2132 | "files": [
2133 | "bootstrap.php"
2134 | ],
2135 | "psr-4": {
2136 | "Symfony\\Polyfill\\Php80\\": ""
2137 | },
2138 | "classmap": [
2139 | "Resources/stubs"
2140 | ]
2141 | },
2142 | "notification-url": "https://packagist.org/downloads/",
2143 | "license": [
2144 | "MIT"
2145 | ],
2146 | "authors": [
2147 | {
2148 | "name": "Ion Bazan",
2149 | "email": "ion.bazan@gmail.com"
2150 | },
2151 | {
2152 | "name": "Nicolas Grekas",
2153 | "email": "p@tchwork.com"
2154 | },
2155 | {
2156 | "name": "Symfony Community",
2157 | "homepage": "https://symfony.com/contributors"
2158 | }
2159 | ],
2160 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
2161 | "homepage": "https://symfony.com",
2162 | "keywords": [
2163 | "compatibility",
2164 | "polyfill",
2165 | "portable",
2166 | "shim"
2167 | ],
2168 | "support": {
2169 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
2170 | },
2171 | "funding": [
2172 | {
2173 | "url": "https://symfony.com/sponsor",
2174 | "type": "custom"
2175 | },
2176 | {
2177 | "url": "https://github.com/fabpot",
2178 | "type": "github"
2179 | },
2180 | {
2181 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2182 | "type": "tidelift"
2183 | }
2184 | ],
2185 | "time": "2025-01-02T08:10:11+00:00"
2186 | },
2187 | {
2188 | "name": "symfony/polyfill-php81",
2189 | "version": "v1.32.0",
2190 | "source": {
2191 | "type": "git",
2192 | "url": "https://github.com/symfony/polyfill-php81.git",
2193 | "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
2194 | },
2195 | "dist": {
2196 | "type": "zip",
2197 | "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
2198 | "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
2199 | "shasum": ""
2200 | },
2201 | "require": {
2202 | "php": ">=7.2"
2203 | },
2204 | "type": "library",
2205 | "extra": {
2206 | "thanks": {
2207 | "url": "https://github.com/symfony/polyfill",
2208 | "name": "symfony/polyfill"
2209 | }
2210 | },
2211 | "autoload": {
2212 | "files": [
2213 | "bootstrap.php"
2214 | ],
2215 | "psr-4": {
2216 | "Symfony\\Polyfill\\Php81\\": ""
2217 | },
2218 | "classmap": [
2219 | "Resources/stubs"
2220 | ]
2221 | },
2222 | "notification-url": "https://packagist.org/downloads/",
2223 | "license": [
2224 | "MIT"
2225 | ],
2226 | "authors": [
2227 | {
2228 | "name": "Nicolas Grekas",
2229 | "email": "p@tchwork.com"
2230 | },
2231 | {
2232 | "name": "Symfony Community",
2233 | "homepage": "https://symfony.com/contributors"
2234 | }
2235 | ],
2236 | "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
2237 | "homepage": "https://symfony.com",
2238 | "keywords": [
2239 | "compatibility",
2240 | "polyfill",
2241 | "portable",
2242 | "shim"
2243 | ],
2244 | "support": {
2245 | "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0"
2246 | },
2247 | "funding": [
2248 | {
2249 | "url": "https://symfony.com/sponsor",
2250 | "type": "custom"
2251 | },
2252 | {
2253 | "url": "https://github.com/fabpot",
2254 | "type": "github"
2255 | },
2256 | {
2257 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2258 | "type": "tidelift"
2259 | }
2260 | ],
2261 | "time": "2024-09-09T11:45:10+00:00"
2262 | },
2263 | {
2264 | "name": "symfony/process",
2265 | "version": "v7.3.0",
2266 | "source": {
2267 | "type": "git",
2268 | "url": "https://github.com/symfony/process.git",
2269 | "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af"
2270 | },
2271 | "dist": {
2272 | "type": "zip",
2273 | "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
2274 | "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
2275 | "shasum": ""
2276 | },
2277 | "require": {
2278 | "php": ">=8.2"
2279 | },
2280 | "type": "library",
2281 | "autoload": {
2282 | "psr-4": {
2283 | "Symfony\\Component\\Process\\": ""
2284 | },
2285 | "exclude-from-classmap": [
2286 | "/Tests/"
2287 | ]
2288 | },
2289 | "notification-url": "https://packagist.org/downloads/",
2290 | "license": [
2291 | "MIT"
2292 | ],
2293 | "authors": [
2294 | {
2295 | "name": "Fabien Potencier",
2296 | "email": "fabien@symfony.com"
2297 | },
2298 | {
2299 | "name": "Symfony Community",
2300 | "homepage": "https://symfony.com/contributors"
2301 | }
2302 | ],
2303 | "description": "Executes commands in sub-processes",
2304 | "homepage": "https://symfony.com",
2305 | "support": {
2306 | "source": "https://github.com/symfony/process/tree/v7.3.0"
2307 | },
2308 | "funding": [
2309 | {
2310 | "url": "https://symfony.com/sponsor",
2311 | "type": "custom"
2312 | },
2313 | {
2314 | "url": "https://github.com/fabpot",
2315 | "type": "github"
2316 | },
2317 | {
2318 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2319 | "type": "tidelift"
2320 | }
2321 | ],
2322 | "time": "2025-04-17T09:11:12+00:00"
2323 | },
2324 | {
2325 | "name": "symfony/service-contracts",
2326 | "version": "v3.6.0",
2327 | "source": {
2328 | "type": "git",
2329 | "url": "https://github.com/symfony/service-contracts.git",
2330 | "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
2331 | },
2332 | "dist": {
2333 | "type": "zip",
2334 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
2335 | "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
2336 | "shasum": ""
2337 | },
2338 | "require": {
2339 | "php": ">=8.1",
2340 | "psr/container": "^1.1|^2.0",
2341 | "symfony/deprecation-contracts": "^2.5|^3"
2342 | },
2343 | "conflict": {
2344 | "ext-psr": "<1.1|>=2"
2345 | },
2346 | "type": "library",
2347 | "extra": {
2348 | "thanks": {
2349 | "url": "https://github.com/symfony/contracts",
2350 | "name": "symfony/contracts"
2351 | },
2352 | "branch-alias": {
2353 | "dev-main": "3.6-dev"
2354 | }
2355 | },
2356 | "autoload": {
2357 | "psr-4": {
2358 | "Symfony\\Contracts\\Service\\": ""
2359 | },
2360 | "exclude-from-classmap": [
2361 | "/Test/"
2362 | ]
2363 | },
2364 | "notification-url": "https://packagist.org/downloads/",
2365 | "license": [
2366 | "MIT"
2367 | ],
2368 | "authors": [
2369 | {
2370 | "name": "Nicolas Grekas",
2371 | "email": "p@tchwork.com"
2372 | },
2373 | {
2374 | "name": "Symfony Community",
2375 | "homepage": "https://symfony.com/contributors"
2376 | }
2377 | ],
2378 | "description": "Generic abstractions related to writing services",
2379 | "homepage": "https://symfony.com",
2380 | "keywords": [
2381 | "abstractions",
2382 | "contracts",
2383 | "decoupling",
2384 | "interfaces",
2385 | "interoperability",
2386 | "standards"
2387 | ],
2388 | "support": {
2389 | "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
2390 | },
2391 | "funding": [
2392 | {
2393 | "url": "https://symfony.com/sponsor",
2394 | "type": "custom"
2395 | },
2396 | {
2397 | "url": "https://github.com/fabpot",
2398 | "type": "github"
2399 | },
2400 | {
2401 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2402 | "type": "tidelift"
2403 | }
2404 | ],
2405 | "time": "2025-04-25T09:37:31+00:00"
2406 | },
2407 | {
2408 | "name": "symfony/stopwatch",
2409 | "version": "v7.3.0",
2410 | "source": {
2411 | "type": "git",
2412 | "url": "https://github.com/symfony/stopwatch.git",
2413 | "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd"
2414 | },
2415 | "dist": {
2416 | "type": "zip",
2417 | "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd",
2418 | "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd",
2419 | "shasum": ""
2420 | },
2421 | "require": {
2422 | "php": ">=8.2",
2423 | "symfony/service-contracts": "^2.5|^3"
2424 | },
2425 | "type": "library",
2426 | "autoload": {
2427 | "psr-4": {
2428 | "Symfony\\Component\\Stopwatch\\": ""
2429 | },
2430 | "exclude-from-classmap": [
2431 | "/Tests/"
2432 | ]
2433 | },
2434 | "notification-url": "https://packagist.org/downloads/",
2435 | "license": [
2436 | "MIT"
2437 | ],
2438 | "authors": [
2439 | {
2440 | "name": "Fabien Potencier",
2441 | "email": "fabien@symfony.com"
2442 | },
2443 | {
2444 | "name": "Symfony Community",
2445 | "homepage": "https://symfony.com/contributors"
2446 | }
2447 | ],
2448 | "description": "Provides a way to profile code",
2449 | "homepage": "https://symfony.com",
2450 | "support": {
2451 | "source": "https://github.com/symfony/stopwatch/tree/v7.3.0"
2452 | },
2453 | "funding": [
2454 | {
2455 | "url": "https://symfony.com/sponsor",
2456 | "type": "custom"
2457 | },
2458 | {
2459 | "url": "https://github.com/fabpot",
2460 | "type": "github"
2461 | },
2462 | {
2463 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2464 | "type": "tidelift"
2465 | }
2466 | ],
2467 | "time": "2025-02-24T10:49:57+00:00"
2468 | },
2469 | {
2470 | "name": "symfony/string",
2471 | "version": "v7.3.2",
2472 | "source": {
2473 | "type": "git",
2474 | "url": "https://github.com/symfony/string.git",
2475 | "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca"
2476 | },
2477 | "dist": {
2478 | "type": "zip",
2479 | "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca",
2480 | "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca",
2481 | "shasum": ""
2482 | },
2483 | "require": {
2484 | "php": ">=8.2",
2485 | "symfony/polyfill-ctype": "~1.8",
2486 | "symfony/polyfill-intl-grapheme": "~1.0",
2487 | "symfony/polyfill-intl-normalizer": "~1.0",
2488 | "symfony/polyfill-mbstring": "~1.0"
2489 | },
2490 | "conflict": {
2491 | "symfony/translation-contracts": "<2.5"
2492 | },
2493 | "require-dev": {
2494 | "symfony/emoji": "^7.1",
2495 | "symfony/error-handler": "^6.4|^7.0",
2496 | "symfony/http-client": "^6.4|^7.0",
2497 | "symfony/intl": "^6.4|^7.0",
2498 | "symfony/translation-contracts": "^2.5|^3.0",
2499 | "symfony/var-exporter": "^6.4|^7.0"
2500 | },
2501 | "type": "library",
2502 | "autoload": {
2503 | "files": [
2504 | "Resources/functions.php"
2505 | ],
2506 | "psr-4": {
2507 | "Symfony\\Component\\String\\": ""
2508 | },
2509 | "exclude-from-classmap": [
2510 | "/Tests/"
2511 | ]
2512 | },
2513 | "notification-url": "https://packagist.org/downloads/",
2514 | "license": [
2515 | "MIT"
2516 | ],
2517 | "authors": [
2518 | {
2519 | "name": "Nicolas Grekas",
2520 | "email": "p@tchwork.com"
2521 | },
2522 | {
2523 | "name": "Symfony Community",
2524 | "homepage": "https://symfony.com/contributors"
2525 | }
2526 | ],
2527 | "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
2528 | "homepage": "https://symfony.com",
2529 | "keywords": [
2530 | "grapheme",
2531 | "i18n",
2532 | "string",
2533 | "unicode",
2534 | "utf-8",
2535 | "utf8"
2536 | ],
2537 | "support": {
2538 | "source": "https://github.com/symfony/string/tree/v7.3.2"
2539 | },
2540 | "funding": [
2541 | {
2542 | "url": "https://symfony.com/sponsor",
2543 | "type": "custom"
2544 | },
2545 | {
2546 | "url": "https://github.com/fabpot",
2547 | "type": "github"
2548 | },
2549 | {
2550 | "url": "https://github.com/nicolas-grekas",
2551 | "type": "github"
2552 | },
2553 | {
2554 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2555 | "type": "tidelift"
2556 | }
2557 | ],
2558 | "time": "2025-07-10T08:47:49+00:00"
2559 | }
2560 | ],
2561 | "packages-dev": [],
2562 | "aliases": [],
2563 | "minimum-stability": "stable",
2564 | "stability-flags": {},
2565 | "prefer-stable": false,
2566 | "prefer-lowest": false,
2567 | "platform": {},
2568 | "platform-dev": {},
2569 | "plugin-api-version": "2.6.0"
2570 | }
2571 |
--------------------------------------------------------------------------------