├── .dockerignore
├── .gitignore
├── .php_cs
├── 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.cache
5 | .phpunit.result.cache
6 |
--------------------------------------------------------------------------------
/.php_cs:
--------------------------------------------------------------------------------
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' => ['sortAlgorithm' => '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 | 'author'
23 | ],
24 | 'void_return' => false,
25 | 'single_trait_insert_per_statement' => false,
26 | 'ternary_to_null_coalescing' => true,
27 | 'pow_to_exponentiation' => false,
28 | 'random_api_migration' => false,
29 | 'declare_strict_types' => false,
30 | 'phpdoc_no_alias_tag' => [
31 | 'replacements' => [
32 | 'type' => 'var',
33 | 'link' => 'see',
34 | ],
35 | ],
36 | 'header_comment' => [
37 | 'commentType' => 'PHPDoc',
38 | 'header' => 'This file is part of the Sclable Xml Lint Package.
39 |
40 | @copyright (c) ' . date('Y') . ' Sclable Business Solutions GmbH
41 |
42 | For the full copyright and license information, please view the LICENSE
43 | file that was distributed with this source code.',
44 | 'location' => 'after_declare_strict',
45 | //'separate' => 'bottom',
46 | ],
47 | ];
48 |
49 | return PhpCsFixer\Config::create()
50 | ->setFinder(
51 | PhpCsFixer\Finder::create()
52 | ->in(__DIR__ . '/src')
53 | ->in(__DIR__ . '/tests')
54 | ->in(__DIR__ . '/bin')
55 | // Note: The pattern is seen relative from one of the `->in()`
56 | // directories. And works for files too this way.
57 | ->notPath('bootstrap.php')
58 | )
59 | ->setRules($fixers);
60 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Sclable XML Lint - Changelog
2 | ============================
3 |
4 | 0.8.0
5 | -----
6 |
7 | * Add support for Symfony 7
8 | * Drop support for Symfony 4
9 | ============================
10 |
11 | 0.7.0
12 | -----
13 |
14 | * Add support for PHP 8.3
15 |
16 | 0.6.0
17 | -----
18 |
19 | * Add support for PHP 8.2
20 | * Drop support for PHP 7.4
21 |
22 | 0.5.0
23 | -----
24 |
25 | * Add support for PHP 8.1
26 | * Drop support for PHP 7.3
27 | * Chores: remove Travis integration
28 |
29 | 0.4.0
30 | -----
31 |
32 | * Add support for PHP 8
33 | * Drop support for PHP 7.2
34 | * Chores: Travis integration update
35 |
36 | 0.3.0
37 | -----
38 |
39 | * Add support for symfony console / finder 5.*
40 | * Drop compatibility for PHP <7.2 and eol symfony versions
41 | * Update test frameworks to latest versions
42 |
43 |
44 | 0.2.4
45 | -----
46 |
47 | * update dependencies to symfony/finder & symfony/console (include 4.*)
48 |
49 |
50 | 0.2.3
51 | -----
52 |
53 | * clean up composer file (move tests to autoload-dev)
54 |
55 | 0.2.2
56 | -----
57 |
58 | * update dependencies to symfony/finder & symfony/console
59 |
60 |
61 | 0.2.1
62 | -----
63 |
64 | * fix a bug where patterns were empty
65 |
66 | 0.2.0
67 | -----
68 |
69 | * validate xml files against XSD schemata (with skip option)
70 | * pattern option
71 |
72 |
73 | 0.1.0
74 | -----
75 |
76 | * cli interface
77 | * lint xml file
78 | * lint files in a directory
79 | * recursive option (default is 'yes')
80 | * exclude option
81 |
--------------------------------------------------------------------------------
/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.3 --build-arg=PHP_VERSION="8.3" .
62 |
63 | # PHP_VERSION: choose between 8.0, 8.1, 8.2 and 8.3
64 | docker build -t xml-lint:php-8.0 --build-arg=PHP_VERSION="8.0" .
65 | docker build -t xml-lint:php-8.1 --build-arg=PHP_VERSION="8.1" .
66 | docker build -t xml-lint:php-8.2 --build-arg=PHP_VERSION="8.2" .
67 | docker build -t xml-lint:php-8.3 --build-arg=PHP_VERSION="8.3" .
68 |
69 | # Run with code style check
70 | docker build -t xml-lint:php-8.3 --build-arg=PHP_VERSION="8.3" --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.3 -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 | "keywords": [
12 | "xml",
13 | "lint",
14 | "cli",
15 | "xsd",
16 | "xml schema"
17 | ],
18 | "bin": ["bin/xmllint"],
19 | "require": {
20 | "php": "8.0.*|8.1.*|8.2.*|8.3.*",
21 | "symfony/console": "5.3.*|5.4.*|6.*|7.*",
22 | "symfony/finder": "5.3.*|5.4.*|6.*|7.*",
23 | "ext-libxml": "*",
24 | "ext-dom": "*"
25 | },
26 | "require-dev": {
27 | "behat/behat": "^3.0",
28 | "phpunit/phpunit": "^9.1"
29 | },
30 | "autoload": {
31 | "psr-4": {
32 | "sclable\\xmlLint\\": "src/php/"
33 | }
34 | },
35 | "autoload-dev": {
36 | "psr-4": {
37 | "sclable\\xmlLint\\tests\\": "tests/"
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | src/php/
6 |
7 |
8 | src/php/console/
9 | src/php/bootstrap.php
10 |
11 |
12 |
13 |
14 | tests/unit
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/php/bootstrap.php:
--------------------------------------------------------------------------------
1 | setDefaultCommand(LintCommand::COMMAND_NAME);
40 | }
41 |
42 | /**
43 | * {@inheritdoc}
44 | */
45 | protected function getDefaultCommands(): array
46 | {
47 | parent::getDefaultCommands();
48 |
49 | return [
50 | new HelpCommand(),
51 | new LintCommand(),
52 | ];
53 | }
54 |
55 | /**
56 | * {@inheritdoc}
57 | *
58 | * @SuppressWarnings(PHPMD.Superglobals)
59 | */
60 | public function run(InputInterface $input = null, OutputInterface $output = null): int
61 | {
62 | if (null === $input) {
63 | // rewrite the input for single command usage
64 | $argv = $_SERVER['argv'];
65 | $scriptName = array_shift($argv);
66 | array_unshift($argv, 'lint');
67 | array_unshift($argv, $scriptName);
68 | $input = new ArgvInput($argv);
69 | }
70 |
71 | return parent::run($input, $output);
72 | }
73 |
74 | /**
75 | * {@inheritdoc}
76 | */
77 | protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output): int
78 | {
79 | if ('version' != $command->getName()) {
80 | $output->writeln($this->getLongVersion());
81 | }
82 |
83 | return parent::doRunCommand($command, $input, $output);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/php/console/command/Command.php:
--------------------------------------------------------------------------------
1 | synopsis[$key])) {
34 | $this->synopsis[$key] = trim(sprintf(
35 | '%s %s',
36 | $_SERVER['PHP_SELF'],
37 | $this->getDefinition()->getSynopsis($short)
38 | ));
39 | }
40 |
41 | return $this->synopsis[$key];
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/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 | /**
31 | * {@inheritdoc}
32 | */
33 | protected function configure()
34 | {
35 | $this->ignoreValidationErrors();
36 |
37 | $this
38 | ->setName('help')
39 | ->setDefinition([
40 | new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
41 | new InputOption(
42 | 'format',
43 | null,
44 | InputOption::VALUE_REQUIRED,
45 | 'The output format (txt, xml, json, or md)',
46 | 'txt'
47 | ),
48 | new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
49 | ])
50 | ->setDescription('Display help')
51 | ->setHelp(<<%command.name% command displays the help.
53 | You can also output the help in other formats by using the --format option:
54 |
55 | php %command.full_name% --help --format=xml
56 | EOF
57 | );
58 | }
59 |
60 | /**
61 | * {@inheritdoc}
62 | */
63 | protected function execute(InputInterface $input, OutputInterface $output): int
64 | {
65 | $this->setCommand(
66 | $this->getApplication()->find(LintCommand::COMMAND_NAME)
67 | );
68 |
69 | return parent::execute($input, $output);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/php/console/command/LintCommand.php:
--------------------------------------------------------------------------------
1 | setName(self::COMMAND_NAME)
62 | ->setDescription('lint an xml file')
63 | ->addArgument(
64 | self::ARGUMENT_FILE,
65 | InputArgument::REQUIRED,
66 | 'the path/to/file.xml to lint a single file or a path/to/directory to lint all xml ' .
67 | 'files in a directory.'
68 | )
69 | ->addOption(
70 | self::OPTION_RECURSIVE,
71 | 'r',
72 | InputOption::VALUE_OPTIONAL,
73 | 'Whether to scan directories recursive.',
74 | true
75 | )
76 | ->addOption(
77 | self::OPTION_EXCLUDE,
78 | 'e',
79 | InputOption::VALUE_REQUIRED,
80 | 'Path(s) to exclude from linting, can be several separated by comma'
81 | )
82 | ->addOption(
83 | self::OPTION_PATTERN,
84 | 'p',
85 | InputOption::VALUE_REQUIRED,
86 | 'Filter files with one or more patterns, e.g.: *.svg,*.xml. Separate patterns by comma.'
87 | )
88 | ->addOption(
89 | self::OPTION_NO_XSD,
90 | 's',
91 | InputOption::VALUE_NONE,
92 | 'Skip downloading and checking against XSD-files.'
93 | )
94 | ;
95 | }
96 |
97 | /**
98 | * {@inheritdoc}
99 | */
100 | protected function execute(InputInterface $input, OutputInterface $output): int
101 | {
102 | $this->start = microtime(true);
103 | $this->output = $output;
104 | $this->input = $input;
105 |
106 | if ($input->getOption(self::OPTION_NO_XSD)) {
107 | $this->validator = ValidationFactory::createLintOnlyValidation();
108 | } else {
109 | $this->validator = ValidationFactory::createDefaultCollection();
110 | }
111 |
112 | $file = $input->getArgument(self::ARGUMENT_FILE);
113 |
114 | $output->writeln('progress: ');
115 | if (is_dir($file)) {
116 | $status = $this->lintDir($file);
117 | } else {
118 | $status = $this->lintFile(new \SplFileInfo($file));
119 | }
120 |
121 | $output->writeln('');
122 |
123 | if (false === $status) {
124 | $this->printReportsOfFilesWithProblems();
125 | }
126 |
127 | $this->output->writeln(sprintf(
128 | PHP_EOL . '%d files / %1.2f seconds done',
129 | count($this->reports),
130 | microtime(true) - $this->start
131 | ));
132 |
133 | return $status ? 0 : 1;
134 | }
135 |
136 | /**
137 | * lint the content of a directory, recursive if defined.
138 | *
139 | * @param string $dir path/to/dir
140 | *
141 | * @return bool
142 | */
143 | private function lintDir($dir)
144 | {
145 | $finder = Finder::create();
146 | $finder->files()
147 | ->in($dir);
148 |
149 | $patterns = $this->input->getOption(self::OPTION_PATTERN);
150 | if (!empty($patterns)) {
151 | $patterns = explode(',', $patterns);
152 | foreach ($patterns as $pattern) {
153 | $finder->name(trim($pattern));
154 | }
155 | } else {
156 | $finder->name('*.xml.dist')
157 | ->name('*.xml');
158 | }
159 |
160 | if (!$this->input->getOption(self::OPTION_RECURSIVE)) {
161 | $finder->depth(0);
162 | }
163 |
164 | if ($this->input->hasOption(self::OPTION_EXCLUDE)) {
165 | $exclude = explode(',', (string) $this->input->getOption(self::OPTION_EXCLUDE));
166 | $finder->exclude($exclude);
167 | }
168 |
169 | $totalFiles = $finder->count();
170 |
171 | $counter = 0;
172 | $ret = true;
173 | /** @var SplFileInfo $file */
174 | foreach ($finder as $file) {
175 | $ret = $this->lintFile($file) && $ret;
176 | if (0 == ++$counter % 30) {
177 | $this->output->writeln(sprintf(
178 | ' %8d/%d %6.2f%%',
179 | $counter,
180 | $totalFiles,
181 | $counter / $totalFiles * 100
182 | ));
183 | }
184 | }
185 |
186 | return $ret;
187 | }
188 |
189 | /**
190 | * format and print the errors from the queue to the output.
191 | */
192 | private function printReportsOfFilesWithProblems()
193 | {
194 | $this->output->writeln(PHP_EOL . 'errors:');
195 |
196 | foreach ($this->reports as $report) {
197 | if (false === $report->hasProblems()) {
198 | continue;
199 | }
200 |
201 | $file = $report->getFile();
202 | $this->output->writeln('file: ' . $file->getPath() . DIRECTORY_SEPARATOR . $file->getFilename());
203 |
204 | foreach ($report->getProblems() as $problem) {
205 | $this->output->write(
206 | ' > ' . $problem->getMessage() . PHP_EOL
207 | );
208 | }
209 |
210 | $this->output->write(' - - ' . PHP_EOL);
211 | }
212 | }
213 |
214 | /**
215 | * lint a file, pass errors to the queue.
216 | *
217 | * @return bool
218 | */
219 | private function lintFile(\SplFileInfo $file)
220 | {
221 | if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
222 | $this->output->write('lint file ' . $file . ' ... ');
223 | }
224 |
225 | $report = FileReport::create($file);
226 | $this->reports[] = $report;
227 | $status = $this->validator->validateFile($report);
228 |
229 | if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
230 | if (false === $status) {
231 | $this->output->writeln('errors');
232 | } else {
233 | $this->output->writeln('passed.');
234 | }
235 | } else {
236 | if (false === $status) {
237 | $this->output->write('F');
238 | } else {
239 | $this->output->write('.');
240 | }
241 | }
242 |
243 | return $status;
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/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 | /**
35 | * {@inheritdoc}
36 | */
37 | public function validateFile(FileReport $report)
38 | {
39 | $realPath = $report->getFile()->getRealPath();
40 |
41 | if (false === is_file($realPath)) {
42 | $report->reportProblem('file not found: ' . $realPath);
43 |
44 | return false;
45 | }
46 |
47 | if (false === is_readable($realPath)) {
48 | $report->reportProblem('file not readable: ' . $realPath);
49 |
50 | return false;
51 | }
52 |
53 | libxml_clear_errors();
54 | $domDoc = new \DOMDocument();
55 | $domDoc->load($realPath, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_PEDANTIC);
56 |
57 | $errors = libxml_get_errors();
58 | foreach ($this->formatter->formatErrors($errors) as $problem) {
59 | $report->reportProblem($problem);
60 | }
61 |
62 | return !$report->hasProblems();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/php/validator/ValidationCollection.php:
--------------------------------------------------------------------------------
1 | collection as $validation) {
31 | $status = $validation->validateFile($report) && $status;
32 | }
33 |
34 | return $status;
35 | }
36 |
37 | public function addValidation(ValidationInterface $validation)
38 | {
39 | $this->collection[] = $validation;
40 |
41 | return $this;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/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 | /**
38 | * {@inheritdoc}
39 | */
40 | public function validateFile(FileReport $report)
41 | {
42 | $file = $report->getFile()->getRealPath();
43 |
44 | if (empty($file)) {
45 | return false;
46 | }
47 |
48 | $domDoc = new \DOMDocument();
49 | $loaded = $domDoc->load($file, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_PEDANTIC);
50 |
51 | if (false === $loaded) {
52 | return false;
53 | }
54 |
55 | $validation = $this->getSchemaValidationFile($domDoc);
56 |
57 | if (false === $validation) {
58 | return true;
59 | }
60 |
61 | $validationSource = $this->getSchemaValidationSource($validation, $report);
62 |
63 | if (false === $validationSource) {
64 | return false;
65 | }
66 |
67 | libxml_clear_errors();
68 | if (true !== $domDoc->schemaValidateSource($validationSource)) {
69 | $errors = libxml_get_errors();
70 | foreach ($this->formatter->formatErrors($errors) as $problem) {
71 | $report->reportProblem($problem);
72 | }
73 |
74 | return false;
75 | }
76 |
77 | return true;
78 | }
79 |
80 | /**
81 | * @param string $filename
82 | * @param FileReport $report
83 | *
84 | * @return bool|string
85 | */
86 | private function getSchemaValidationSource($filename, $report)
87 | {
88 | if ((0 === preg_match('/^(http|https|ftp):/i', $filename))) {
89 | if (false === file_exists($filename)) {
90 | $filename = $report->getFile()->getPath() . '/' . $filename;
91 | }
92 | if (!is_readable($filename)) {
93 | $report->reportProblem('unable to validate, schema file is not readable: ' . $filename);
94 |
95 | return false;
96 | }
97 | }
98 |
99 | if (isset($this->cache[$filename])) {
100 | return $this->cache[$filename];
101 | }
102 |
103 | $validationSource = @file_get_contents($filename);
104 |
105 | if (false === $validationSource) {
106 | $report->reportProblem('unable to load schema file from: ' . $filename);
107 |
108 | return false;
109 | }
110 |
111 | if (empty($validationSource)) {
112 | $report->reportProblem(sprintf('xsd validation file is empty ("%s").', $filename));
113 |
114 | return false;
115 | }
116 |
117 | return $this->cache[$filename] = $validationSource;
118 | }
119 |
120 | /**
121 | * @return bool|string
122 | */
123 | private function getSchemaValidationFile(\DOMDocument $document)
124 | {
125 | $firstChild = $this->getFirstChild($document);
126 | // @codeCoverageIgnoreStart
127 | if (false === $firstChild) {
128 | return false;
129 | }
130 | // @codeCoverageIgnoreEnd
131 |
132 | $attribute = $firstChild->getAttribute('xsi:noNamespaceSchemaLocation');
133 |
134 | if (empty($attribute)) {
135 | return false;
136 | }
137 |
138 | return $attribute;
139 | }
140 |
141 | /**
142 | * @return bool|\DOMElement
143 | */
144 | private function getFirstChild(\DOMDocument $document)
145 | {
146 | foreach ($document->childNodes as $child) {
147 | if ($child instanceof \DOMElement) {
148 | return $child;
149 | // @codeCoverageIgnoreStart
150 | }
151 | }
152 |
153 | return false;
154 | // @codeCoverageIgnoreEnd
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/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 | * @param $file
56 | */
57 | public function theFile($file)
58 | {
59 | $this->file = dirname(__DIR__) . '/_testdata/' . $file;
60 | }
61 |
62 | /**
63 | * @When I run lint
64 | */
65 | public function iRunLint()
66 | {
67 | $this->exitCode = $this->commandTester->execute([
68 | 'file' => $this->file,
69 | ]);
70 | }
71 |
72 | /**
73 | * @Then I have a return code :code
74 | *
75 | * @param $code
76 | *
77 | * @throws \Exception
78 | */
79 | public function iHaveAReturnCode($code)
80 | {
81 | $code = (int) $code;
82 |
83 | if (null === $this->exitCode) {
84 | echo $this->commandTester->getDisplay();
85 | throw new \Exception('the return code was NULL.');
86 | }
87 |
88 | if ($this->exitCode !== $code) {
89 | echo $this->commandTester->getDisplay();
90 | throw new \Exception(sprintf("the return code does not match. \n Expected: %s\n Actual: %s", $code, $this->exitCode));
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/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/8a114be04aa8cfb34aaea7dc5bb40c6ec96bcaf7/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 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": "^2.17"
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": "bd4e716f45e67e6f741fc209581c20eb",
8 | "packages": [
9 | {
10 | "name": "composer/semver",
11 | "version": "3.2.4",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/composer/semver.git",
15 | "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464",
20 | "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": "^5.3.2 || ^7.0 || ^8.0"
25 | },
26 | "require-dev": {
27 | "phpstan/phpstan": "^0.12.54",
28 | "symfony/phpunit-bridge": "^4.2 || ^5"
29 | },
30 | "type": "library",
31 | "extra": {
32 | "branch-alias": {
33 | "dev-main": "3.x-dev"
34 | }
35 | },
36 | "autoload": {
37 | "psr-4": {
38 | "Composer\\Semver\\": "src"
39 | }
40 | },
41 | "notification-url": "https://packagist.org/downloads/",
42 | "license": [
43 | "MIT"
44 | ],
45 | "authors": [
46 | {
47 | "name": "Nils Adermann",
48 | "email": "naderman@naderman.de",
49 | "homepage": "http://www.naderman.de"
50 | },
51 | {
52 | "name": "Jordi Boggiano",
53 | "email": "j.boggiano@seld.be",
54 | "homepage": "http://seld.be"
55 | },
56 | {
57 | "name": "Rob Bast",
58 | "email": "rob.bast@gmail.com",
59 | "homepage": "http://robbast.nl"
60 | }
61 | ],
62 | "description": "Semver library that offers utilities, version constraint parsing and validation.",
63 | "keywords": [
64 | "semantic",
65 | "semver",
66 | "validation",
67 | "versioning"
68 | ],
69 | "support": {
70 | "irc": "irc://irc.freenode.org/composer",
71 | "issues": "https://github.com/composer/semver/issues",
72 | "source": "https://github.com/composer/semver/tree/3.2.4"
73 | },
74 | "funding": [
75 | {
76 | "url": "https://packagist.com",
77 | "type": "custom"
78 | },
79 | {
80 | "url": "https://github.com/composer",
81 | "type": "github"
82 | },
83 | {
84 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
85 | "type": "tidelift"
86 | }
87 | ],
88 | "time": "2020-11-13T08:59:24+00:00"
89 | },
90 | {
91 | "name": "composer/xdebug-handler",
92 | "version": "1.4.5",
93 | "source": {
94 | "type": "git",
95 | "url": "https://github.com/composer/xdebug-handler.git",
96 | "reference": "f28d44c286812c714741478d968104c5e604a1d4"
97 | },
98 | "dist": {
99 | "type": "zip",
100 | "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4",
101 | "reference": "f28d44c286812c714741478d968104c5e604a1d4",
102 | "shasum": ""
103 | },
104 | "require": {
105 | "php": "^5.3.2 || ^7.0 || ^8.0",
106 | "psr/log": "^1.0"
107 | },
108 | "require-dev": {
109 | "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
110 | },
111 | "type": "library",
112 | "autoload": {
113 | "psr-4": {
114 | "Composer\\XdebugHandler\\": "src"
115 | }
116 | },
117 | "notification-url": "https://packagist.org/downloads/",
118 | "license": [
119 | "MIT"
120 | ],
121 | "authors": [
122 | {
123 | "name": "John Stevenson",
124 | "email": "john-stevenson@blueyonder.co.uk"
125 | }
126 | ],
127 | "description": "Restarts a process without Xdebug.",
128 | "keywords": [
129 | "Xdebug",
130 | "performance"
131 | ],
132 | "support": {
133 | "irc": "irc://irc.freenode.org/composer",
134 | "issues": "https://github.com/composer/xdebug-handler/issues",
135 | "source": "https://github.com/composer/xdebug-handler/tree/1.4.5"
136 | },
137 | "funding": [
138 | {
139 | "url": "https://packagist.com",
140 | "type": "custom"
141 | },
142 | {
143 | "url": "https://github.com/composer",
144 | "type": "github"
145 | },
146 | {
147 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
148 | "type": "tidelift"
149 | }
150 | ],
151 | "time": "2020-11-13T08:04:11+00:00"
152 | },
153 | {
154 | "name": "doctrine/annotations",
155 | "version": "1.11.1",
156 | "source": {
157 | "type": "git",
158 | "url": "https://github.com/doctrine/annotations.git",
159 | "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad"
160 | },
161 | "dist": {
162 | "type": "zip",
163 | "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad",
164 | "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad",
165 | "shasum": ""
166 | },
167 | "require": {
168 | "doctrine/lexer": "1.*",
169 | "ext-tokenizer": "*",
170 | "php": "^7.1 || ^8.0"
171 | },
172 | "require-dev": {
173 | "doctrine/cache": "1.*",
174 | "doctrine/coding-standard": "^6.0 || ^8.1",
175 | "phpstan/phpstan": "^0.12.20",
176 | "phpunit/phpunit": "^7.5 || ^9.1.5"
177 | },
178 | "type": "library",
179 | "extra": {
180 | "branch-alias": {
181 | "dev-master": "1.11.x-dev"
182 | }
183 | },
184 | "autoload": {
185 | "psr-4": {
186 | "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
187 | }
188 | },
189 | "notification-url": "https://packagist.org/downloads/",
190 | "license": [
191 | "MIT"
192 | ],
193 | "authors": [
194 | {
195 | "name": "Guilherme Blanco",
196 | "email": "guilhermeblanco@gmail.com"
197 | },
198 | {
199 | "name": "Roman Borschel",
200 | "email": "roman@code-factory.org"
201 | },
202 | {
203 | "name": "Benjamin Eberlei",
204 | "email": "kontakt@beberlei.de"
205 | },
206 | {
207 | "name": "Jonathan Wage",
208 | "email": "jonwage@gmail.com"
209 | },
210 | {
211 | "name": "Johannes Schmitt",
212 | "email": "schmittjoh@gmail.com"
213 | }
214 | ],
215 | "description": "Docblock Annotations Parser",
216 | "homepage": "https://www.doctrine-project.org/projects/annotations.html",
217 | "keywords": [
218 | "annotations",
219 | "docblock",
220 | "parser"
221 | ],
222 | "support": {
223 | "issues": "https://github.com/doctrine/annotations/issues",
224 | "source": "https://github.com/doctrine/annotations/tree/1.11.1"
225 | },
226 | "time": "2020-10-26T10:28:16+00:00"
227 | },
228 | {
229 | "name": "doctrine/lexer",
230 | "version": "1.2.1",
231 | "source": {
232 | "type": "git",
233 | "url": "https://github.com/doctrine/lexer.git",
234 | "reference": "e864bbf5904cb8f5bb334f99209b48018522f042"
235 | },
236 | "dist": {
237 | "type": "zip",
238 | "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042",
239 | "reference": "e864bbf5904cb8f5bb334f99209b48018522f042",
240 | "shasum": ""
241 | },
242 | "require": {
243 | "php": "^7.2 || ^8.0"
244 | },
245 | "require-dev": {
246 | "doctrine/coding-standard": "^6.0",
247 | "phpstan/phpstan": "^0.11.8",
248 | "phpunit/phpunit": "^8.2"
249 | },
250 | "type": "library",
251 | "extra": {
252 | "branch-alias": {
253 | "dev-master": "1.2.x-dev"
254 | }
255 | },
256 | "autoload": {
257 | "psr-4": {
258 | "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
259 | }
260 | },
261 | "notification-url": "https://packagist.org/downloads/",
262 | "license": [
263 | "MIT"
264 | ],
265 | "authors": [
266 | {
267 | "name": "Guilherme Blanco",
268 | "email": "guilhermeblanco@gmail.com"
269 | },
270 | {
271 | "name": "Roman Borschel",
272 | "email": "roman@code-factory.org"
273 | },
274 | {
275 | "name": "Johannes Schmitt",
276 | "email": "schmittjoh@gmail.com"
277 | }
278 | ],
279 | "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
280 | "homepage": "https://www.doctrine-project.org/projects/lexer.html",
281 | "keywords": [
282 | "annotations",
283 | "docblock",
284 | "lexer",
285 | "parser",
286 | "php"
287 | ],
288 | "support": {
289 | "issues": "https://github.com/doctrine/lexer/issues",
290 | "source": "https://github.com/doctrine/lexer/tree/1.2.1"
291 | },
292 | "funding": [
293 | {
294 | "url": "https://www.doctrine-project.org/sponsorship.html",
295 | "type": "custom"
296 | },
297 | {
298 | "url": "https://www.patreon.com/phpdoctrine",
299 | "type": "patreon"
300 | },
301 | {
302 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
303 | "type": "tidelift"
304 | }
305 | ],
306 | "time": "2020-05-25T17:44:05+00:00"
307 | },
308 | {
309 | "name": "friendsofphp/php-cs-fixer",
310 | "version": "v2.17.1",
311 | "source": {
312 | "type": "git",
313 | "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
314 | "reference": "5198b7308ed63f26799387fd7f3901c3db6bd7fd"
315 | },
316 | "dist": {
317 | "type": "zip",
318 | "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/5198b7308ed63f26799387fd7f3901c3db6bd7fd",
319 | "reference": "5198b7308ed63f26799387fd7f3901c3db6bd7fd",
320 | "shasum": ""
321 | },
322 | "require": {
323 | "composer/semver": "^1.4 || ^2.0 || ^3.0",
324 | "composer/xdebug-handler": "^1.2",
325 | "doctrine/annotations": "^1.2",
326 | "ext-json": "*",
327 | "ext-tokenizer": "*",
328 | "php": "^5.6 || ^7.0 || ^8.0",
329 | "php-cs-fixer/diff": "^1.3",
330 | "symfony/console": "^3.4.43 || ^4.1.6 || ^5.0",
331 | "symfony/event-dispatcher": "^3.0 || ^4.0 || ^5.0",
332 | "symfony/filesystem": "^3.0 || ^4.0 || ^5.0",
333 | "symfony/finder": "^3.0 || ^4.0 || ^5.0",
334 | "symfony/options-resolver": "^3.0 || ^4.0 || ^5.0",
335 | "symfony/polyfill-php70": "^1.0",
336 | "symfony/polyfill-php72": "^1.4",
337 | "symfony/process": "^3.0 || ^4.0 || ^5.0",
338 | "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0"
339 | },
340 | "require-dev": {
341 | "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0",
342 | "justinrainbow/json-schema": "^5.0",
343 | "keradus/cli-executor": "^1.4",
344 | "mikey179/vfsstream": "^1.6",
345 | "php-coveralls/php-coveralls": "^2.4.1",
346 | "php-cs-fixer/accessible-object": "^1.0",
347 | "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2",
348 | "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1",
349 | "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.1",
350 | "phpunitgoodpractices/polyfill": "^1.5",
351 | "phpunitgoodpractices/traits": "^1.9.1",
352 | "symfony/phpunit-bridge": "^5.1",
353 | "symfony/yaml": "^3.0 || ^4.0 || ^5.0"
354 | },
355 | "suggest": {
356 | "ext-dom": "For handling output formats in XML",
357 | "ext-mbstring": "For handling non-UTF8 characters.",
358 | "php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.",
359 | "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.",
360 | "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible."
361 | },
362 | "bin": [
363 | "php-cs-fixer"
364 | ],
365 | "type": "application",
366 | "autoload": {
367 | "psr-4": {
368 | "PhpCsFixer\\": "src/"
369 | },
370 | "classmap": [
371 | "tests/Test/AbstractFixerTestCase.php",
372 | "tests/Test/AbstractIntegrationCaseFactory.php",
373 | "tests/Test/AbstractIntegrationTestCase.php",
374 | "tests/Test/Assert/AssertTokensTrait.php",
375 | "tests/Test/IntegrationCase.php",
376 | "tests/Test/IntegrationCaseFactory.php",
377 | "tests/Test/IntegrationCaseFactoryInterface.php",
378 | "tests/Test/InternalIntegrationCaseFactory.php",
379 | "tests/Test/IsIdenticalConstraint.php",
380 | "tests/TestCase.php"
381 | ]
382 | },
383 | "notification-url": "https://packagist.org/downloads/",
384 | "license": [
385 | "MIT"
386 | ],
387 | "authors": [
388 | {
389 | "name": "Fabien Potencier",
390 | "email": "fabien@symfony.com"
391 | },
392 | {
393 | "name": "Dariusz Rumiński",
394 | "email": "dariusz.ruminski@gmail.com"
395 | }
396 | ],
397 | "description": "A tool to automatically fix PHP code style",
398 | "support": {
399 | "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues",
400 | "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.17.1"
401 | },
402 | "funding": [
403 | {
404 | "url": "https://github.com/keradus",
405 | "type": "github"
406 | }
407 | ],
408 | "time": "2020-12-08T13:47:02+00:00"
409 | },
410 | {
411 | "name": "php-cs-fixer/diff",
412 | "version": "v1.3.1",
413 | "source": {
414 | "type": "git",
415 | "url": "https://github.com/PHP-CS-Fixer/diff.git",
416 | "reference": "dbd31aeb251639ac0b9e7e29405c1441907f5759"
417 | },
418 | "dist": {
419 | "type": "zip",
420 | "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/dbd31aeb251639ac0b9e7e29405c1441907f5759",
421 | "reference": "dbd31aeb251639ac0b9e7e29405c1441907f5759",
422 | "shasum": ""
423 | },
424 | "require": {
425 | "php": "^5.6 || ^7.0 || ^8.0"
426 | },
427 | "require-dev": {
428 | "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0",
429 | "symfony/process": "^3.3"
430 | },
431 | "type": "library",
432 | "autoload": {
433 | "classmap": [
434 | "src/"
435 | ]
436 | },
437 | "notification-url": "https://packagist.org/downloads/",
438 | "license": [
439 | "BSD-3-Clause"
440 | ],
441 | "authors": [
442 | {
443 | "name": "Sebastian Bergmann",
444 | "email": "sebastian@phpunit.de"
445 | },
446 | {
447 | "name": "Kore Nordmann",
448 | "email": "mail@kore-nordmann.de"
449 | },
450 | {
451 | "name": "SpacePossum"
452 | }
453 | ],
454 | "description": "sebastian/diff v2 backport support for PHP5.6",
455 | "homepage": "https://github.com/PHP-CS-Fixer",
456 | "keywords": [
457 | "diff"
458 | ],
459 | "support": {
460 | "issues": "https://github.com/PHP-CS-Fixer/diff/issues",
461 | "source": "https://github.com/PHP-CS-Fixer/diff/tree/v1.3.1"
462 | },
463 | "time": "2020-10-14T08:39:05+00:00"
464 | },
465 | {
466 | "name": "psr/container",
467 | "version": "1.0.0",
468 | "source": {
469 | "type": "git",
470 | "url": "https://github.com/php-fig/container.git",
471 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
472 | },
473 | "dist": {
474 | "type": "zip",
475 | "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
476 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
477 | "shasum": ""
478 | },
479 | "require": {
480 | "php": ">=5.3.0"
481 | },
482 | "type": "library",
483 | "extra": {
484 | "branch-alias": {
485 | "dev-master": "1.0.x-dev"
486 | }
487 | },
488 | "autoload": {
489 | "psr-4": {
490 | "Psr\\Container\\": "src/"
491 | }
492 | },
493 | "notification-url": "https://packagist.org/downloads/",
494 | "license": [
495 | "MIT"
496 | ],
497 | "authors": [
498 | {
499 | "name": "PHP-FIG",
500 | "homepage": "http://www.php-fig.org/"
501 | }
502 | ],
503 | "description": "Common Container Interface (PHP FIG PSR-11)",
504 | "homepage": "https://github.com/php-fig/container",
505 | "keywords": [
506 | "PSR-11",
507 | "container",
508 | "container-interface",
509 | "container-interop",
510 | "psr"
511 | ],
512 | "support": {
513 | "issues": "https://github.com/php-fig/container/issues",
514 | "source": "https://github.com/php-fig/container/tree/master"
515 | },
516 | "time": "2017-02-14T16:28:37+00:00"
517 | },
518 | {
519 | "name": "psr/event-dispatcher",
520 | "version": "1.0.0",
521 | "source": {
522 | "type": "git",
523 | "url": "https://github.com/php-fig/event-dispatcher.git",
524 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
525 | },
526 | "dist": {
527 | "type": "zip",
528 | "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
529 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
530 | "shasum": ""
531 | },
532 | "require": {
533 | "php": ">=7.2.0"
534 | },
535 | "type": "library",
536 | "extra": {
537 | "branch-alias": {
538 | "dev-master": "1.0.x-dev"
539 | }
540 | },
541 | "autoload": {
542 | "psr-4": {
543 | "Psr\\EventDispatcher\\": "src/"
544 | }
545 | },
546 | "notification-url": "https://packagist.org/downloads/",
547 | "license": [
548 | "MIT"
549 | ],
550 | "authors": [
551 | {
552 | "name": "PHP-FIG",
553 | "homepage": "http://www.php-fig.org/"
554 | }
555 | ],
556 | "description": "Standard interfaces for event handling.",
557 | "keywords": [
558 | "events",
559 | "psr",
560 | "psr-14"
561 | ],
562 | "support": {
563 | "issues": "https://github.com/php-fig/event-dispatcher/issues",
564 | "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
565 | },
566 | "time": "2019-01-08T18:20:26+00:00"
567 | },
568 | {
569 | "name": "psr/log",
570 | "version": "1.1.3",
571 | "source": {
572 | "type": "git",
573 | "url": "https://github.com/php-fig/log.git",
574 | "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
575 | },
576 | "dist": {
577 | "type": "zip",
578 | "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
579 | "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
580 | "shasum": ""
581 | },
582 | "require": {
583 | "php": ">=5.3.0"
584 | },
585 | "type": "library",
586 | "extra": {
587 | "branch-alias": {
588 | "dev-master": "1.1.x-dev"
589 | }
590 | },
591 | "autoload": {
592 | "psr-4": {
593 | "Psr\\Log\\": "Psr/Log/"
594 | }
595 | },
596 | "notification-url": "https://packagist.org/downloads/",
597 | "license": [
598 | "MIT"
599 | ],
600 | "authors": [
601 | {
602 | "name": "PHP-FIG",
603 | "homepage": "http://www.php-fig.org/"
604 | }
605 | ],
606 | "description": "Common interface for logging libraries",
607 | "homepage": "https://github.com/php-fig/log",
608 | "keywords": [
609 | "log",
610 | "psr",
611 | "psr-3"
612 | ],
613 | "support": {
614 | "source": "https://github.com/php-fig/log/tree/1.1.3"
615 | },
616 | "time": "2020-03-23T09:12:05+00:00"
617 | },
618 | {
619 | "name": "symfony/console",
620 | "version": "v5.2.0",
621 | "source": {
622 | "type": "git",
623 | "url": "https://github.com/symfony/console.git",
624 | "reference": "3e0564fb08d44a98bd5f1960204c958e57bd586b"
625 | },
626 | "dist": {
627 | "type": "zip",
628 | "url": "https://api.github.com/repos/symfony/console/zipball/3e0564fb08d44a98bd5f1960204c958e57bd586b",
629 | "reference": "3e0564fb08d44a98bd5f1960204c958e57bd586b",
630 | "shasum": ""
631 | },
632 | "require": {
633 | "php": ">=7.2.5",
634 | "symfony/polyfill-mbstring": "~1.0",
635 | "symfony/polyfill-php73": "^1.8",
636 | "symfony/polyfill-php80": "^1.15",
637 | "symfony/service-contracts": "^1.1|^2",
638 | "symfony/string": "^5.1"
639 | },
640 | "conflict": {
641 | "symfony/dependency-injection": "<4.4",
642 | "symfony/dotenv": "<5.1",
643 | "symfony/event-dispatcher": "<4.4",
644 | "symfony/lock": "<4.4",
645 | "symfony/process": "<4.4"
646 | },
647 | "provide": {
648 | "psr/log-implementation": "1.0"
649 | },
650 | "require-dev": {
651 | "psr/log": "~1.0",
652 | "symfony/config": "^4.4|^5.0",
653 | "symfony/dependency-injection": "^4.4|^5.0",
654 | "symfony/event-dispatcher": "^4.4|^5.0",
655 | "symfony/lock": "^4.4|^5.0",
656 | "symfony/process": "^4.4|^5.0",
657 | "symfony/var-dumper": "^4.4|^5.0"
658 | },
659 | "suggest": {
660 | "psr/log": "For using the console logger",
661 | "symfony/event-dispatcher": "",
662 | "symfony/lock": "",
663 | "symfony/process": ""
664 | },
665 | "type": "library",
666 | "autoload": {
667 | "psr-4": {
668 | "Symfony\\Component\\Console\\": ""
669 | },
670 | "exclude-from-classmap": [
671 | "/Tests/"
672 | ]
673 | },
674 | "notification-url": "https://packagist.org/downloads/",
675 | "license": [
676 | "MIT"
677 | ],
678 | "authors": [
679 | {
680 | "name": "Fabien Potencier",
681 | "email": "fabien@symfony.com"
682 | },
683 | {
684 | "name": "Symfony Community",
685 | "homepage": "https://symfony.com/contributors"
686 | }
687 | ],
688 | "description": "Symfony Console Component",
689 | "homepage": "https://symfony.com",
690 | "keywords": [
691 | "cli",
692 | "command line",
693 | "console",
694 | "terminal"
695 | ],
696 | "support": {
697 | "source": "https://github.com/symfony/console/tree/v5.2.0"
698 | },
699 | "funding": [
700 | {
701 | "url": "https://symfony.com/sponsor",
702 | "type": "custom"
703 | },
704 | {
705 | "url": "https://github.com/fabpot",
706 | "type": "github"
707 | },
708 | {
709 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
710 | "type": "tidelift"
711 | }
712 | ],
713 | "time": "2020-11-28T11:24:18+00:00"
714 | },
715 | {
716 | "name": "symfony/deprecation-contracts",
717 | "version": "v2.2.0",
718 | "source": {
719 | "type": "git",
720 | "url": "https://github.com/symfony/deprecation-contracts.git",
721 | "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665"
722 | },
723 | "dist": {
724 | "type": "zip",
725 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665",
726 | "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665",
727 | "shasum": ""
728 | },
729 | "require": {
730 | "php": ">=7.1"
731 | },
732 | "type": "library",
733 | "extra": {
734 | "branch-alias": {
735 | "dev-master": "2.2-dev"
736 | },
737 | "thanks": {
738 | "name": "symfony/contracts",
739 | "url": "https://github.com/symfony/contracts"
740 | }
741 | },
742 | "autoload": {
743 | "files": [
744 | "function.php"
745 | ]
746 | },
747 | "notification-url": "https://packagist.org/downloads/",
748 | "license": [
749 | "MIT"
750 | ],
751 | "authors": [
752 | {
753 | "name": "Nicolas Grekas",
754 | "email": "p@tchwork.com"
755 | },
756 | {
757 | "name": "Symfony Community",
758 | "homepage": "https://symfony.com/contributors"
759 | }
760 | ],
761 | "description": "A generic function and convention to trigger deprecation notices",
762 | "homepage": "https://symfony.com",
763 | "support": {
764 | "source": "https://github.com/symfony/deprecation-contracts/tree/master"
765 | },
766 | "funding": [
767 | {
768 | "url": "https://symfony.com/sponsor",
769 | "type": "custom"
770 | },
771 | {
772 | "url": "https://github.com/fabpot",
773 | "type": "github"
774 | },
775 | {
776 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
777 | "type": "tidelift"
778 | }
779 | ],
780 | "time": "2020-09-07T11:33:47+00:00"
781 | },
782 | {
783 | "name": "symfony/event-dispatcher",
784 | "version": "v5.2.0",
785 | "source": {
786 | "type": "git",
787 | "url": "https://github.com/symfony/event-dispatcher.git",
788 | "reference": "aa13a09811e6d2ad43f8fb336bebdb7691d85d3c"
789 | },
790 | "dist": {
791 | "type": "zip",
792 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/aa13a09811e6d2ad43f8fb336bebdb7691d85d3c",
793 | "reference": "aa13a09811e6d2ad43f8fb336bebdb7691d85d3c",
794 | "shasum": ""
795 | },
796 | "require": {
797 | "php": ">=7.2.5",
798 | "symfony/deprecation-contracts": "^2.1",
799 | "symfony/event-dispatcher-contracts": "^2",
800 | "symfony/polyfill-php80": "^1.15"
801 | },
802 | "conflict": {
803 | "symfony/dependency-injection": "<4.4"
804 | },
805 | "provide": {
806 | "psr/event-dispatcher-implementation": "1.0",
807 | "symfony/event-dispatcher-implementation": "2.0"
808 | },
809 | "require-dev": {
810 | "psr/log": "~1.0",
811 | "symfony/config": "^4.4|^5.0",
812 | "symfony/dependency-injection": "^4.4|^5.0",
813 | "symfony/error-handler": "^4.4|^5.0",
814 | "symfony/expression-language": "^4.4|^5.0",
815 | "symfony/http-foundation": "^4.4|^5.0",
816 | "symfony/service-contracts": "^1.1|^2",
817 | "symfony/stopwatch": "^4.4|^5.0"
818 | },
819 | "suggest": {
820 | "symfony/dependency-injection": "",
821 | "symfony/http-kernel": ""
822 | },
823 | "type": "library",
824 | "autoload": {
825 | "psr-4": {
826 | "Symfony\\Component\\EventDispatcher\\": ""
827 | },
828 | "exclude-from-classmap": [
829 | "/Tests/"
830 | ]
831 | },
832 | "notification-url": "https://packagist.org/downloads/",
833 | "license": [
834 | "MIT"
835 | ],
836 | "authors": [
837 | {
838 | "name": "Fabien Potencier",
839 | "email": "fabien@symfony.com"
840 | },
841 | {
842 | "name": "Symfony Community",
843 | "homepage": "https://symfony.com/contributors"
844 | }
845 | ],
846 | "description": "Symfony EventDispatcher Component",
847 | "homepage": "https://symfony.com",
848 | "support": {
849 | "source": "https://github.com/symfony/event-dispatcher/tree/v5.2.0"
850 | },
851 | "funding": [
852 | {
853 | "url": "https://symfony.com/sponsor",
854 | "type": "custom"
855 | },
856 | {
857 | "url": "https://github.com/fabpot",
858 | "type": "github"
859 | },
860 | {
861 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
862 | "type": "tidelift"
863 | }
864 | ],
865 | "time": "2020-11-01T16:14:45+00:00"
866 | },
867 | {
868 | "name": "symfony/event-dispatcher-contracts",
869 | "version": "v2.2.0",
870 | "source": {
871 | "type": "git",
872 | "url": "https://github.com/symfony/event-dispatcher-contracts.git",
873 | "reference": "0ba7d54483095a198fa51781bc608d17e84dffa2"
874 | },
875 | "dist": {
876 | "type": "zip",
877 | "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ba7d54483095a198fa51781bc608d17e84dffa2",
878 | "reference": "0ba7d54483095a198fa51781bc608d17e84dffa2",
879 | "shasum": ""
880 | },
881 | "require": {
882 | "php": ">=7.2.5",
883 | "psr/event-dispatcher": "^1"
884 | },
885 | "suggest": {
886 | "symfony/event-dispatcher-implementation": ""
887 | },
888 | "type": "library",
889 | "extra": {
890 | "branch-alias": {
891 | "dev-master": "2.2-dev"
892 | },
893 | "thanks": {
894 | "name": "symfony/contracts",
895 | "url": "https://github.com/symfony/contracts"
896 | }
897 | },
898 | "autoload": {
899 | "psr-4": {
900 | "Symfony\\Contracts\\EventDispatcher\\": ""
901 | }
902 | },
903 | "notification-url": "https://packagist.org/downloads/",
904 | "license": [
905 | "MIT"
906 | ],
907 | "authors": [
908 | {
909 | "name": "Nicolas Grekas",
910 | "email": "p@tchwork.com"
911 | },
912 | {
913 | "name": "Symfony Community",
914 | "homepage": "https://symfony.com/contributors"
915 | }
916 | ],
917 | "description": "Generic abstractions related to dispatching event",
918 | "homepage": "https://symfony.com",
919 | "keywords": [
920 | "abstractions",
921 | "contracts",
922 | "decoupling",
923 | "interfaces",
924 | "interoperability",
925 | "standards"
926 | ],
927 | "support": {
928 | "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.2.0"
929 | },
930 | "funding": [
931 | {
932 | "url": "https://symfony.com/sponsor",
933 | "type": "custom"
934 | },
935 | {
936 | "url": "https://github.com/fabpot",
937 | "type": "github"
938 | },
939 | {
940 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
941 | "type": "tidelift"
942 | }
943 | ],
944 | "time": "2020-09-07T11:33:47+00:00"
945 | },
946 | {
947 | "name": "symfony/filesystem",
948 | "version": "v5.2.0",
949 | "source": {
950 | "type": "git",
951 | "url": "https://github.com/symfony/filesystem.git",
952 | "reference": "bb92ba7f38b037e531908590a858a04d85c0e238"
953 | },
954 | "dist": {
955 | "type": "zip",
956 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/bb92ba7f38b037e531908590a858a04d85c0e238",
957 | "reference": "bb92ba7f38b037e531908590a858a04d85c0e238",
958 | "shasum": ""
959 | },
960 | "require": {
961 | "php": ">=7.2.5",
962 | "symfony/polyfill-ctype": "~1.8"
963 | },
964 | "type": "library",
965 | "autoload": {
966 | "psr-4": {
967 | "Symfony\\Component\\Filesystem\\": ""
968 | },
969 | "exclude-from-classmap": [
970 | "/Tests/"
971 | ]
972 | },
973 | "notification-url": "https://packagist.org/downloads/",
974 | "license": [
975 | "MIT"
976 | ],
977 | "authors": [
978 | {
979 | "name": "Fabien Potencier",
980 | "email": "fabien@symfony.com"
981 | },
982 | {
983 | "name": "Symfony Community",
984 | "homepage": "https://symfony.com/contributors"
985 | }
986 | ],
987 | "description": "Symfony Filesystem Component",
988 | "homepage": "https://symfony.com",
989 | "support": {
990 | "source": "https://github.com/symfony/filesystem/tree/v5.2.0"
991 | },
992 | "funding": [
993 | {
994 | "url": "https://symfony.com/sponsor",
995 | "type": "custom"
996 | },
997 | {
998 | "url": "https://github.com/fabpot",
999 | "type": "github"
1000 | },
1001 | {
1002 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1003 | "type": "tidelift"
1004 | }
1005 | ],
1006 | "time": "2020-11-12T09:58:18+00:00"
1007 | },
1008 | {
1009 | "name": "symfony/finder",
1010 | "version": "v5.2.0",
1011 | "source": {
1012 | "type": "git",
1013 | "url": "https://github.com/symfony/finder.git",
1014 | "reference": "fd8305521692f27eae3263895d1ef1571c71a78d"
1015 | },
1016 | "dist": {
1017 | "type": "zip",
1018 | "url": "https://api.github.com/repos/symfony/finder/zipball/fd8305521692f27eae3263895d1ef1571c71a78d",
1019 | "reference": "fd8305521692f27eae3263895d1ef1571c71a78d",
1020 | "shasum": ""
1021 | },
1022 | "require": {
1023 | "php": ">=7.2.5"
1024 | },
1025 | "type": "library",
1026 | "autoload": {
1027 | "psr-4": {
1028 | "Symfony\\Component\\Finder\\": ""
1029 | },
1030 | "exclude-from-classmap": [
1031 | "/Tests/"
1032 | ]
1033 | },
1034 | "notification-url": "https://packagist.org/downloads/",
1035 | "license": [
1036 | "MIT"
1037 | ],
1038 | "authors": [
1039 | {
1040 | "name": "Fabien Potencier",
1041 | "email": "fabien@symfony.com"
1042 | },
1043 | {
1044 | "name": "Symfony Community",
1045 | "homepage": "https://symfony.com/contributors"
1046 | }
1047 | ],
1048 | "description": "Symfony Finder Component",
1049 | "homepage": "https://symfony.com",
1050 | "support": {
1051 | "source": "https://github.com/symfony/finder/tree/v5.2.0"
1052 | },
1053 | "funding": [
1054 | {
1055 | "url": "https://symfony.com/sponsor",
1056 | "type": "custom"
1057 | },
1058 | {
1059 | "url": "https://github.com/fabpot",
1060 | "type": "github"
1061 | },
1062 | {
1063 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1064 | "type": "tidelift"
1065 | }
1066 | ],
1067 | "time": "2020-11-18T09:42:36+00:00"
1068 | },
1069 | {
1070 | "name": "symfony/options-resolver",
1071 | "version": "v5.2.0",
1072 | "source": {
1073 | "type": "git",
1074 | "url": "https://github.com/symfony/options-resolver.git",
1075 | "reference": "87a2a4a766244e796dd9cb9d6f58c123358cd986"
1076 | },
1077 | "dist": {
1078 | "type": "zip",
1079 | "url": "https://api.github.com/repos/symfony/options-resolver/zipball/87a2a4a766244e796dd9cb9d6f58c123358cd986",
1080 | "reference": "87a2a4a766244e796dd9cb9d6f58c123358cd986",
1081 | "shasum": ""
1082 | },
1083 | "require": {
1084 | "php": ">=7.2.5",
1085 | "symfony/deprecation-contracts": "^2.1",
1086 | "symfony/polyfill-php73": "~1.0",
1087 | "symfony/polyfill-php80": "^1.15"
1088 | },
1089 | "type": "library",
1090 | "autoload": {
1091 | "psr-4": {
1092 | "Symfony\\Component\\OptionsResolver\\": ""
1093 | },
1094 | "exclude-from-classmap": [
1095 | "/Tests/"
1096 | ]
1097 | },
1098 | "notification-url": "https://packagist.org/downloads/",
1099 | "license": [
1100 | "MIT"
1101 | ],
1102 | "authors": [
1103 | {
1104 | "name": "Fabien Potencier",
1105 | "email": "fabien@symfony.com"
1106 | },
1107 | {
1108 | "name": "Symfony Community",
1109 | "homepage": "https://symfony.com/contributors"
1110 | }
1111 | ],
1112 | "description": "Symfony OptionsResolver Component",
1113 | "homepage": "https://symfony.com",
1114 | "keywords": [
1115 | "config",
1116 | "configuration",
1117 | "options"
1118 | ],
1119 | "support": {
1120 | "source": "https://github.com/symfony/options-resolver/tree/v5.2.0"
1121 | },
1122 | "funding": [
1123 | {
1124 | "url": "https://symfony.com/sponsor",
1125 | "type": "custom"
1126 | },
1127 | {
1128 | "url": "https://github.com/fabpot",
1129 | "type": "github"
1130 | },
1131 | {
1132 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1133 | "type": "tidelift"
1134 | }
1135 | ],
1136 | "time": "2020-10-24T12:08:07+00:00"
1137 | },
1138 | {
1139 | "name": "symfony/polyfill-ctype",
1140 | "version": "v1.20.0",
1141 | "source": {
1142 | "type": "git",
1143 | "url": "https://github.com/symfony/polyfill-ctype.git",
1144 | "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41"
1145 | },
1146 | "dist": {
1147 | "type": "zip",
1148 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41",
1149 | "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41",
1150 | "shasum": ""
1151 | },
1152 | "require": {
1153 | "php": ">=7.1"
1154 | },
1155 | "suggest": {
1156 | "ext-ctype": "For best performance"
1157 | },
1158 | "type": "library",
1159 | "extra": {
1160 | "branch-alias": {
1161 | "dev-main": "1.20-dev"
1162 | },
1163 | "thanks": {
1164 | "name": "symfony/polyfill",
1165 | "url": "https://github.com/symfony/polyfill"
1166 | }
1167 | },
1168 | "autoload": {
1169 | "psr-4": {
1170 | "Symfony\\Polyfill\\Ctype\\": ""
1171 | },
1172 | "files": [
1173 | "bootstrap.php"
1174 | ]
1175 | },
1176 | "notification-url": "https://packagist.org/downloads/",
1177 | "license": [
1178 | "MIT"
1179 | ],
1180 | "authors": [
1181 | {
1182 | "name": "Gert de Pagter",
1183 | "email": "BackEndTea@gmail.com"
1184 | },
1185 | {
1186 | "name": "Symfony Community",
1187 | "homepage": "https://symfony.com/contributors"
1188 | }
1189 | ],
1190 | "description": "Symfony polyfill for ctype functions",
1191 | "homepage": "https://symfony.com",
1192 | "keywords": [
1193 | "compatibility",
1194 | "ctype",
1195 | "polyfill",
1196 | "portable"
1197 | ],
1198 | "support": {
1199 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.20.0"
1200 | },
1201 | "funding": [
1202 | {
1203 | "url": "https://symfony.com/sponsor",
1204 | "type": "custom"
1205 | },
1206 | {
1207 | "url": "https://github.com/fabpot",
1208 | "type": "github"
1209 | },
1210 | {
1211 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1212 | "type": "tidelift"
1213 | }
1214 | ],
1215 | "time": "2020-10-23T14:02:19+00:00"
1216 | },
1217 | {
1218 | "name": "symfony/polyfill-intl-grapheme",
1219 | "version": "v1.20.0",
1220 | "source": {
1221 | "type": "git",
1222 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
1223 | "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c"
1224 | },
1225 | "dist": {
1226 | "type": "zip",
1227 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c",
1228 | "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c",
1229 | "shasum": ""
1230 | },
1231 | "require": {
1232 | "php": ">=7.1"
1233 | },
1234 | "suggest": {
1235 | "ext-intl": "For best performance"
1236 | },
1237 | "type": "library",
1238 | "extra": {
1239 | "branch-alias": {
1240 | "dev-main": "1.20-dev"
1241 | },
1242 | "thanks": {
1243 | "name": "symfony/polyfill",
1244 | "url": "https://github.com/symfony/polyfill"
1245 | }
1246 | },
1247 | "autoload": {
1248 | "psr-4": {
1249 | "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
1250 | },
1251 | "files": [
1252 | "bootstrap.php"
1253 | ]
1254 | },
1255 | "notification-url": "https://packagist.org/downloads/",
1256 | "license": [
1257 | "MIT"
1258 | ],
1259 | "authors": [
1260 | {
1261 | "name": "Nicolas Grekas",
1262 | "email": "p@tchwork.com"
1263 | },
1264 | {
1265 | "name": "Symfony Community",
1266 | "homepage": "https://symfony.com/contributors"
1267 | }
1268 | ],
1269 | "description": "Symfony polyfill for intl's grapheme_* functions",
1270 | "homepage": "https://symfony.com",
1271 | "keywords": [
1272 | "compatibility",
1273 | "grapheme",
1274 | "intl",
1275 | "polyfill",
1276 | "portable",
1277 | "shim"
1278 | ],
1279 | "support": {
1280 | "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.20.0"
1281 | },
1282 | "funding": [
1283 | {
1284 | "url": "https://symfony.com/sponsor",
1285 | "type": "custom"
1286 | },
1287 | {
1288 | "url": "https://github.com/fabpot",
1289 | "type": "github"
1290 | },
1291 | {
1292 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1293 | "type": "tidelift"
1294 | }
1295 | ],
1296 | "time": "2020-10-23T14:02:19+00:00"
1297 | },
1298 | {
1299 | "name": "symfony/polyfill-intl-normalizer",
1300 | "version": "v1.20.0",
1301 | "source": {
1302 | "type": "git",
1303 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
1304 | "reference": "727d1096295d807c309fb01a851577302394c897"
1305 | },
1306 | "dist": {
1307 | "type": "zip",
1308 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897",
1309 | "reference": "727d1096295d807c309fb01a851577302394c897",
1310 | "shasum": ""
1311 | },
1312 | "require": {
1313 | "php": ">=7.1"
1314 | },
1315 | "suggest": {
1316 | "ext-intl": "For best performance"
1317 | },
1318 | "type": "library",
1319 | "extra": {
1320 | "branch-alias": {
1321 | "dev-main": "1.20-dev"
1322 | },
1323 | "thanks": {
1324 | "name": "symfony/polyfill",
1325 | "url": "https://github.com/symfony/polyfill"
1326 | }
1327 | },
1328 | "autoload": {
1329 | "psr-4": {
1330 | "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
1331 | },
1332 | "files": [
1333 | "bootstrap.php"
1334 | ],
1335 | "classmap": [
1336 | "Resources/stubs"
1337 | ]
1338 | },
1339 | "notification-url": "https://packagist.org/downloads/",
1340 | "license": [
1341 | "MIT"
1342 | ],
1343 | "authors": [
1344 | {
1345 | "name": "Nicolas Grekas",
1346 | "email": "p@tchwork.com"
1347 | },
1348 | {
1349 | "name": "Symfony Community",
1350 | "homepage": "https://symfony.com/contributors"
1351 | }
1352 | ],
1353 | "description": "Symfony polyfill for intl's Normalizer class and related functions",
1354 | "homepage": "https://symfony.com",
1355 | "keywords": [
1356 | "compatibility",
1357 | "intl",
1358 | "normalizer",
1359 | "polyfill",
1360 | "portable",
1361 | "shim"
1362 | ],
1363 | "support": {
1364 | "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.20.0"
1365 | },
1366 | "funding": [
1367 | {
1368 | "url": "https://symfony.com/sponsor",
1369 | "type": "custom"
1370 | },
1371 | {
1372 | "url": "https://github.com/fabpot",
1373 | "type": "github"
1374 | },
1375 | {
1376 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1377 | "type": "tidelift"
1378 | }
1379 | ],
1380 | "time": "2020-10-23T14:02:19+00:00"
1381 | },
1382 | {
1383 | "name": "symfony/polyfill-mbstring",
1384 | "version": "v1.20.0",
1385 | "source": {
1386 | "type": "git",
1387 | "url": "https://github.com/symfony/polyfill-mbstring.git",
1388 | "reference": "39d483bdf39be819deabf04ec872eb0b2410b531"
1389 | },
1390 | "dist": {
1391 | "type": "zip",
1392 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531",
1393 | "reference": "39d483bdf39be819deabf04ec872eb0b2410b531",
1394 | "shasum": ""
1395 | },
1396 | "require": {
1397 | "php": ">=7.1"
1398 | },
1399 | "suggest": {
1400 | "ext-mbstring": "For best performance"
1401 | },
1402 | "type": "library",
1403 | "extra": {
1404 | "branch-alias": {
1405 | "dev-main": "1.20-dev"
1406 | },
1407 | "thanks": {
1408 | "name": "symfony/polyfill",
1409 | "url": "https://github.com/symfony/polyfill"
1410 | }
1411 | },
1412 | "autoload": {
1413 | "psr-4": {
1414 | "Symfony\\Polyfill\\Mbstring\\": ""
1415 | },
1416 | "files": [
1417 | "bootstrap.php"
1418 | ]
1419 | },
1420 | "notification-url": "https://packagist.org/downloads/",
1421 | "license": [
1422 | "MIT"
1423 | ],
1424 | "authors": [
1425 | {
1426 | "name": "Nicolas Grekas",
1427 | "email": "p@tchwork.com"
1428 | },
1429 | {
1430 | "name": "Symfony Community",
1431 | "homepage": "https://symfony.com/contributors"
1432 | }
1433 | ],
1434 | "description": "Symfony polyfill for the Mbstring extension",
1435 | "homepage": "https://symfony.com",
1436 | "keywords": [
1437 | "compatibility",
1438 | "mbstring",
1439 | "polyfill",
1440 | "portable",
1441 | "shim"
1442 | ],
1443 | "support": {
1444 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.20.0"
1445 | },
1446 | "funding": [
1447 | {
1448 | "url": "https://symfony.com/sponsor",
1449 | "type": "custom"
1450 | },
1451 | {
1452 | "url": "https://github.com/fabpot",
1453 | "type": "github"
1454 | },
1455 | {
1456 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1457 | "type": "tidelift"
1458 | }
1459 | ],
1460 | "time": "2020-10-23T14:02:19+00:00"
1461 | },
1462 | {
1463 | "name": "symfony/polyfill-php70",
1464 | "version": "v1.20.0",
1465 | "source": {
1466 | "type": "git",
1467 | "url": "https://github.com/symfony/polyfill-php70.git",
1468 | "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644"
1469 | },
1470 | "dist": {
1471 | "type": "zip",
1472 | "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644",
1473 | "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644",
1474 | "shasum": ""
1475 | },
1476 | "require": {
1477 | "php": ">=7.1"
1478 | },
1479 | "type": "metapackage",
1480 | "extra": {
1481 | "branch-alias": {
1482 | "dev-main": "1.20-dev"
1483 | },
1484 | "thanks": {
1485 | "name": "symfony/polyfill",
1486 | "url": "https://github.com/symfony/polyfill"
1487 | }
1488 | },
1489 | "notification-url": "https://packagist.org/downloads/",
1490 | "license": [
1491 | "MIT"
1492 | ],
1493 | "authors": [
1494 | {
1495 | "name": "Nicolas Grekas",
1496 | "email": "p@tchwork.com"
1497 | },
1498 | {
1499 | "name": "Symfony Community",
1500 | "homepage": "https://symfony.com/contributors"
1501 | }
1502 | ],
1503 | "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
1504 | "homepage": "https://symfony.com",
1505 | "keywords": [
1506 | "compatibility",
1507 | "polyfill",
1508 | "portable",
1509 | "shim"
1510 | ],
1511 | "support": {
1512 | "source": "https://github.com/symfony/polyfill-php70/tree/v1.20.0"
1513 | },
1514 | "funding": [
1515 | {
1516 | "url": "https://symfony.com/sponsor",
1517 | "type": "custom"
1518 | },
1519 | {
1520 | "url": "https://github.com/fabpot",
1521 | "type": "github"
1522 | },
1523 | {
1524 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1525 | "type": "tidelift"
1526 | }
1527 | ],
1528 | "time": "2020-10-23T14:02:19+00:00"
1529 | },
1530 | {
1531 | "name": "symfony/polyfill-php72",
1532 | "version": "v1.20.0",
1533 | "source": {
1534 | "type": "git",
1535 | "url": "https://github.com/symfony/polyfill-php72.git",
1536 | "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930"
1537 | },
1538 | "dist": {
1539 | "type": "zip",
1540 | "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930",
1541 | "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930",
1542 | "shasum": ""
1543 | },
1544 | "require": {
1545 | "php": ">=7.1"
1546 | },
1547 | "type": "library",
1548 | "extra": {
1549 | "branch-alias": {
1550 | "dev-main": "1.20-dev"
1551 | },
1552 | "thanks": {
1553 | "name": "symfony/polyfill",
1554 | "url": "https://github.com/symfony/polyfill"
1555 | }
1556 | },
1557 | "autoload": {
1558 | "psr-4": {
1559 | "Symfony\\Polyfill\\Php72\\": ""
1560 | },
1561 | "files": [
1562 | "bootstrap.php"
1563 | ]
1564 | },
1565 | "notification-url": "https://packagist.org/downloads/",
1566 | "license": [
1567 | "MIT"
1568 | ],
1569 | "authors": [
1570 | {
1571 | "name": "Nicolas Grekas",
1572 | "email": "p@tchwork.com"
1573 | },
1574 | {
1575 | "name": "Symfony Community",
1576 | "homepage": "https://symfony.com/contributors"
1577 | }
1578 | ],
1579 | "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
1580 | "homepage": "https://symfony.com",
1581 | "keywords": [
1582 | "compatibility",
1583 | "polyfill",
1584 | "portable",
1585 | "shim"
1586 | ],
1587 | "support": {
1588 | "source": "https://github.com/symfony/polyfill-php72/tree/v1.20.0"
1589 | },
1590 | "funding": [
1591 | {
1592 | "url": "https://symfony.com/sponsor",
1593 | "type": "custom"
1594 | },
1595 | {
1596 | "url": "https://github.com/fabpot",
1597 | "type": "github"
1598 | },
1599 | {
1600 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1601 | "type": "tidelift"
1602 | }
1603 | ],
1604 | "time": "2020-10-23T14:02:19+00:00"
1605 | },
1606 | {
1607 | "name": "symfony/polyfill-php73",
1608 | "version": "v1.20.0",
1609 | "source": {
1610 | "type": "git",
1611 | "url": "https://github.com/symfony/polyfill-php73.git",
1612 | "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed"
1613 | },
1614 | "dist": {
1615 | "type": "zip",
1616 | "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/8ff431c517be11c78c48a39a66d37431e26a6bed",
1617 | "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed",
1618 | "shasum": ""
1619 | },
1620 | "require": {
1621 | "php": ">=7.1"
1622 | },
1623 | "type": "library",
1624 | "extra": {
1625 | "branch-alias": {
1626 | "dev-main": "1.20-dev"
1627 | },
1628 | "thanks": {
1629 | "name": "symfony/polyfill",
1630 | "url": "https://github.com/symfony/polyfill"
1631 | }
1632 | },
1633 | "autoload": {
1634 | "psr-4": {
1635 | "Symfony\\Polyfill\\Php73\\": ""
1636 | },
1637 | "files": [
1638 | "bootstrap.php"
1639 | ],
1640 | "classmap": [
1641 | "Resources/stubs"
1642 | ]
1643 | },
1644 | "notification-url": "https://packagist.org/downloads/",
1645 | "license": [
1646 | "MIT"
1647 | ],
1648 | "authors": [
1649 | {
1650 | "name": "Nicolas Grekas",
1651 | "email": "p@tchwork.com"
1652 | },
1653 | {
1654 | "name": "Symfony Community",
1655 | "homepage": "https://symfony.com/contributors"
1656 | }
1657 | ],
1658 | "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
1659 | "homepage": "https://symfony.com",
1660 | "keywords": [
1661 | "compatibility",
1662 | "polyfill",
1663 | "portable",
1664 | "shim"
1665 | ],
1666 | "support": {
1667 | "source": "https://github.com/symfony/polyfill-php73/tree/v1.20.0"
1668 | },
1669 | "funding": [
1670 | {
1671 | "url": "https://symfony.com/sponsor",
1672 | "type": "custom"
1673 | },
1674 | {
1675 | "url": "https://github.com/fabpot",
1676 | "type": "github"
1677 | },
1678 | {
1679 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1680 | "type": "tidelift"
1681 | }
1682 | ],
1683 | "time": "2020-10-23T14:02:19+00:00"
1684 | },
1685 | {
1686 | "name": "symfony/polyfill-php80",
1687 | "version": "v1.20.0",
1688 | "source": {
1689 | "type": "git",
1690 | "url": "https://github.com/symfony/polyfill-php80.git",
1691 | "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de"
1692 | },
1693 | "dist": {
1694 | "type": "zip",
1695 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de",
1696 | "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de",
1697 | "shasum": ""
1698 | },
1699 | "require": {
1700 | "php": ">=7.1"
1701 | },
1702 | "type": "library",
1703 | "extra": {
1704 | "branch-alias": {
1705 | "dev-main": "1.20-dev"
1706 | },
1707 | "thanks": {
1708 | "name": "symfony/polyfill",
1709 | "url": "https://github.com/symfony/polyfill"
1710 | }
1711 | },
1712 | "autoload": {
1713 | "psr-4": {
1714 | "Symfony\\Polyfill\\Php80\\": ""
1715 | },
1716 | "files": [
1717 | "bootstrap.php"
1718 | ],
1719 | "classmap": [
1720 | "Resources/stubs"
1721 | ]
1722 | },
1723 | "notification-url": "https://packagist.org/downloads/",
1724 | "license": [
1725 | "MIT"
1726 | ],
1727 | "authors": [
1728 | {
1729 | "name": "Ion Bazan",
1730 | "email": "ion.bazan@gmail.com"
1731 | },
1732 | {
1733 | "name": "Nicolas Grekas",
1734 | "email": "p@tchwork.com"
1735 | },
1736 | {
1737 | "name": "Symfony Community",
1738 | "homepage": "https://symfony.com/contributors"
1739 | }
1740 | ],
1741 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
1742 | "homepage": "https://symfony.com",
1743 | "keywords": [
1744 | "compatibility",
1745 | "polyfill",
1746 | "portable",
1747 | "shim"
1748 | ],
1749 | "support": {
1750 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.20.0"
1751 | },
1752 | "funding": [
1753 | {
1754 | "url": "https://symfony.com/sponsor",
1755 | "type": "custom"
1756 | },
1757 | {
1758 | "url": "https://github.com/fabpot",
1759 | "type": "github"
1760 | },
1761 | {
1762 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1763 | "type": "tidelift"
1764 | }
1765 | ],
1766 | "time": "2020-10-23T14:02:19+00:00"
1767 | },
1768 | {
1769 | "name": "symfony/process",
1770 | "version": "v5.2.0",
1771 | "source": {
1772 | "type": "git",
1773 | "url": "https://github.com/symfony/process.git",
1774 | "reference": "240e74140d4d956265048f3025c0aecbbc302d54"
1775 | },
1776 | "dist": {
1777 | "type": "zip",
1778 | "url": "https://api.github.com/repos/symfony/process/zipball/240e74140d4d956265048f3025c0aecbbc302d54",
1779 | "reference": "240e74140d4d956265048f3025c0aecbbc302d54",
1780 | "shasum": ""
1781 | },
1782 | "require": {
1783 | "php": ">=7.2.5",
1784 | "symfony/polyfill-php80": "^1.15"
1785 | },
1786 | "type": "library",
1787 | "autoload": {
1788 | "psr-4": {
1789 | "Symfony\\Component\\Process\\": ""
1790 | },
1791 | "exclude-from-classmap": [
1792 | "/Tests/"
1793 | ]
1794 | },
1795 | "notification-url": "https://packagist.org/downloads/",
1796 | "license": [
1797 | "MIT"
1798 | ],
1799 | "authors": [
1800 | {
1801 | "name": "Fabien Potencier",
1802 | "email": "fabien@symfony.com"
1803 | },
1804 | {
1805 | "name": "Symfony Community",
1806 | "homepage": "https://symfony.com/contributors"
1807 | }
1808 | ],
1809 | "description": "Symfony Process Component",
1810 | "homepage": "https://symfony.com",
1811 | "support": {
1812 | "source": "https://github.com/symfony/process/tree/v5.2.0"
1813 | },
1814 | "funding": [
1815 | {
1816 | "url": "https://symfony.com/sponsor",
1817 | "type": "custom"
1818 | },
1819 | {
1820 | "url": "https://github.com/fabpot",
1821 | "type": "github"
1822 | },
1823 | {
1824 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1825 | "type": "tidelift"
1826 | }
1827 | ],
1828 | "time": "2020-11-02T15:47:15+00:00"
1829 | },
1830 | {
1831 | "name": "symfony/service-contracts",
1832 | "version": "v2.2.0",
1833 | "source": {
1834 | "type": "git",
1835 | "url": "https://github.com/symfony/service-contracts.git",
1836 | "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1"
1837 | },
1838 | "dist": {
1839 | "type": "zip",
1840 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1",
1841 | "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1",
1842 | "shasum": ""
1843 | },
1844 | "require": {
1845 | "php": ">=7.2.5",
1846 | "psr/container": "^1.0"
1847 | },
1848 | "suggest": {
1849 | "symfony/service-implementation": ""
1850 | },
1851 | "type": "library",
1852 | "extra": {
1853 | "branch-alias": {
1854 | "dev-master": "2.2-dev"
1855 | },
1856 | "thanks": {
1857 | "name": "symfony/contracts",
1858 | "url": "https://github.com/symfony/contracts"
1859 | }
1860 | },
1861 | "autoload": {
1862 | "psr-4": {
1863 | "Symfony\\Contracts\\Service\\": ""
1864 | }
1865 | },
1866 | "notification-url": "https://packagist.org/downloads/",
1867 | "license": [
1868 | "MIT"
1869 | ],
1870 | "authors": [
1871 | {
1872 | "name": "Nicolas Grekas",
1873 | "email": "p@tchwork.com"
1874 | },
1875 | {
1876 | "name": "Symfony Community",
1877 | "homepage": "https://symfony.com/contributors"
1878 | }
1879 | ],
1880 | "description": "Generic abstractions related to writing services",
1881 | "homepage": "https://symfony.com",
1882 | "keywords": [
1883 | "abstractions",
1884 | "contracts",
1885 | "decoupling",
1886 | "interfaces",
1887 | "interoperability",
1888 | "standards"
1889 | ],
1890 | "support": {
1891 | "source": "https://github.com/symfony/service-contracts/tree/master"
1892 | },
1893 | "funding": [
1894 | {
1895 | "url": "https://symfony.com/sponsor",
1896 | "type": "custom"
1897 | },
1898 | {
1899 | "url": "https://github.com/fabpot",
1900 | "type": "github"
1901 | },
1902 | {
1903 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1904 | "type": "tidelift"
1905 | }
1906 | ],
1907 | "time": "2020-09-07T11:33:47+00:00"
1908 | },
1909 | {
1910 | "name": "symfony/stopwatch",
1911 | "version": "v5.2.0",
1912 | "source": {
1913 | "type": "git",
1914 | "url": "https://github.com/symfony/stopwatch.git",
1915 | "reference": "2b105c0354f39a63038a1d8bf776ee92852813af"
1916 | },
1917 | "dist": {
1918 | "type": "zip",
1919 | "url": "https://api.github.com/repos/symfony/stopwatch/zipball/2b105c0354f39a63038a1d8bf776ee92852813af",
1920 | "reference": "2b105c0354f39a63038a1d8bf776ee92852813af",
1921 | "shasum": ""
1922 | },
1923 | "require": {
1924 | "php": ">=7.2.5",
1925 | "symfony/service-contracts": "^1.0|^2"
1926 | },
1927 | "type": "library",
1928 | "autoload": {
1929 | "psr-4": {
1930 | "Symfony\\Component\\Stopwatch\\": ""
1931 | },
1932 | "exclude-from-classmap": [
1933 | "/Tests/"
1934 | ]
1935 | },
1936 | "notification-url": "https://packagist.org/downloads/",
1937 | "license": [
1938 | "MIT"
1939 | ],
1940 | "authors": [
1941 | {
1942 | "name": "Fabien Potencier",
1943 | "email": "fabien@symfony.com"
1944 | },
1945 | {
1946 | "name": "Symfony Community",
1947 | "homepage": "https://symfony.com/contributors"
1948 | }
1949 | ],
1950 | "description": "Symfony Stopwatch Component",
1951 | "homepage": "https://symfony.com",
1952 | "support": {
1953 | "source": "https://github.com/symfony/stopwatch/tree/v5.2.0"
1954 | },
1955 | "funding": [
1956 | {
1957 | "url": "https://symfony.com/sponsor",
1958 | "type": "custom"
1959 | },
1960 | {
1961 | "url": "https://github.com/fabpot",
1962 | "type": "github"
1963 | },
1964 | {
1965 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1966 | "type": "tidelift"
1967 | }
1968 | ],
1969 | "time": "2020-11-01T16:14:45+00:00"
1970 | },
1971 | {
1972 | "name": "symfony/string",
1973 | "version": "v5.2.0",
1974 | "source": {
1975 | "type": "git",
1976 | "url": "https://github.com/symfony/string.git",
1977 | "reference": "40e975edadd4e32cd16f3753b3bad65d9ac48242"
1978 | },
1979 | "dist": {
1980 | "type": "zip",
1981 | "url": "https://api.github.com/repos/symfony/string/zipball/40e975edadd4e32cd16f3753b3bad65d9ac48242",
1982 | "reference": "40e975edadd4e32cd16f3753b3bad65d9ac48242",
1983 | "shasum": ""
1984 | },
1985 | "require": {
1986 | "php": ">=7.2.5",
1987 | "symfony/polyfill-ctype": "~1.8",
1988 | "symfony/polyfill-intl-grapheme": "~1.0",
1989 | "symfony/polyfill-intl-normalizer": "~1.0",
1990 | "symfony/polyfill-mbstring": "~1.0",
1991 | "symfony/polyfill-php80": "~1.15"
1992 | },
1993 | "require-dev": {
1994 | "symfony/error-handler": "^4.4|^5.0",
1995 | "symfony/http-client": "^4.4|^5.0",
1996 | "symfony/translation-contracts": "^1.1|^2",
1997 | "symfony/var-exporter": "^4.4|^5.0"
1998 | },
1999 | "type": "library",
2000 | "autoload": {
2001 | "psr-4": {
2002 | "Symfony\\Component\\String\\": ""
2003 | },
2004 | "files": [
2005 | "Resources/functions.php"
2006 | ],
2007 | "exclude-from-classmap": [
2008 | "/Tests/"
2009 | ]
2010 | },
2011 | "notification-url": "https://packagist.org/downloads/",
2012 | "license": [
2013 | "MIT"
2014 | ],
2015 | "authors": [
2016 | {
2017 | "name": "Nicolas Grekas",
2018 | "email": "p@tchwork.com"
2019 | },
2020 | {
2021 | "name": "Symfony Community",
2022 | "homepage": "https://symfony.com/contributors"
2023 | }
2024 | ],
2025 | "description": "Symfony String component",
2026 | "homepage": "https://symfony.com",
2027 | "keywords": [
2028 | "grapheme",
2029 | "i18n",
2030 | "string",
2031 | "unicode",
2032 | "utf-8",
2033 | "utf8"
2034 | ],
2035 | "support": {
2036 | "source": "https://github.com/symfony/string/tree/v5.2.0"
2037 | },
2038 | "funding": [
2039 | {
2040 | "url": "https://symfony.com/sponsor",
2041 | "type": "custom"
2042 | },
2043 | {
2044 | "url": "https://github.com/fabpot",
2045 | "type": "github"
2046 | },
2047 | {
2048 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2049 | "type": "tidelift"
2050 | }
2051 | ],
2052 | "time": "2020-10-24T12:08:07+00:00"
2053 | }
2054 | ],
2055 | "packages-dev": [],
2056 | "aliases": [],
2057 | "minimum-stability": "stable",
2058 | "stability-flags": [],
2059 | "prefer-stable": false,
2060 | "prefer-lowest": false,
2061 | "platform": [],
2062 | "platform-dev": [],
2063 | "plugin-api-version": "2.0.0"
2064 | }
2065 |
--------------------------------------------------------------------------------