Merge branch '4.4' into 5.0
* 4.4: (23 commits) [Filesystem] Handle paths on different drives [WebProfiler] Do not add src-elem CSP directives if they do not exist [Yaml] fix parse error when unindented collections contain a comment Execute docker dependent tests with github actions Update exception.html.php [3.4][Inflector] Improve testSingularize() argument name [Inflector] Fix testPluralize() arguments names [PhpUnitBridge] fix PHP 5.3 compat again Skip validation when email is an empty object fix sr_Latn translation [Validator] fix lazy property usage. Fix annotation [Debug][ErrorHandler] cleanup phpunit.xml.dist files [Translation] Fix for translation:update command updating ICU messages [PhpUnitBridge] fix compat with PHP 5.3 bumped Symfony version to 4.4.9 updated VERSION for 4.4.8 updated CHANGELOG for 4.4.8 provide a useful message when extension types don't match [Cache] Fixed not supported Redis eviction policies ...
This commit is contained in:
commit
ae226ee34b
|
@ -0,0 +1,101 @@
|
||||||
|
name: Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
integration:
|
||||||
|
name: Integration
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
php: ['7.1', '7.4']
|
||||||
|
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: redis:6.0.0
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
redis-cluster:
|
||||||
|
image: grokzen/redis-cluster:5.0.4
|
||||||
|
ports:
|
||||||
|
- 7000:7000
|
||||||
|
- 7001:7001
|
||||||
|
- 7002:7002
|
||||||
|
- 7003:7003
|
||||||
|
- 7004:7004
|
||||||
|
- 7005:7005
|
||||||
|
- 7006:7006
|
||||||
|
- 7007:7007
|
||||||
|
env:
|
||||||
|
STANDALONE: true
|
||||||
|
memcached:
|
||||||
|
image: memcached:1.6.5
|
||||||
|
ports:
|
||||||
|
- 11211:11211
|
||||||
|
rabbitmq:
|
||||||
|
image: rabbitmq:3.8.3
|
||||||
|
ports:
|
||||||
|
- 5672:5672
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
coverage: "none"
|
||||||
|
extensions: "memcached,redis,xsl"
|
||||||
|
ini-values: "memory_limit=-1"
|
||||||
|
php-version: "${{ matrix.php }}"
|
||||||
|
tools: flex
|
||||||
|
|
||||||
|
- name: Configure composer
|
||||||
|
run: |
|
||||||
|
([ -d ~/.composer ] || mkdir ~/.composer) && cp .github/composer-config.json ~/.composer/config.json
|
||||||
|
SYMFONY_VERSION=$(cat composer.json | grep '^ *\"dev-master\". *\"[1-9]' | grep -o '[0-9.]*')
|
||||||
|
echo "::set-env name=SYMFONY_VERSION::$SYMFONY_VERSION"
|
||||||
|
echo "::set-env name=COMPOSER_ROOT_VERSION::$SYMFONY_VERSION.x-dev"
|
||||||
|
|
||||||
|
- name: Determine composer cache directory
|
||||||
|
id: composer-cache
|
||||||
|
run: echo "::set-output name=directory::$(composer config cache-dir)"
|
||||||
|
|
||||||
|
- name: Cache composer dependencies
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.composer-cache.outputs.directory }}
|
||||||
|
key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||||
|
restore-keys: ${{ matrix.php }}-composer-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
echo "::group::composer update"
|
||||||
|
composer update --no-progress --no-suggest --ansi
|
||||||
|
echo "::endgroup::"
|
||||||
|
echo "::group::install phpunit"
|
||||||
|
./phpunit install
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: ./phpunit --verbose --group integration
|
||||||
|
env:
|
||||||
|
SYMFONY_DEPRECATIONS_HELPER: 'max[indirect]=7'
|
||||||
|
REDIS_HOST: localhost
|
||||||
|
REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005'
|
||||||
|
MESSENGER_REDIS_DSN: redis://127.0.0.1:7006/messages
|
||||||
|
MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages
|
||||||
|
MEMCACHED_HOST: localhost
|
||||||
|
|
||||||
|
- name: Run HTTP push tests
|
||||||
|
if: matrix.php == '7.4'
|
||||||
|
run: |
|
||||||
|
[ -d .phpunit ] && mv .phpunit .phpunit.bak
|
||||||
|
wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/vulcain_0.1.3_Linux_x86_64.tar.gz -O - | tar xz && mv vulcain /usr/local/bin
|
||||||
|
docker run --rm -e COMPOSER_ROOT_VERSION -e SYMFONY_VERSION -v $(pwd):/app -v $(which composer):/usr/local/bin/composer -v /usr/local/bin/vulcain:/usr/local/bin/vulcain -w /app php:7.4-alpine ./phpunit --verbose src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push
|
||||||
|
sudo rm -rf .phpunit
|
||||||
|
[ -d .phpunit.bak ] && mv .phpunit.bak .phpunit
|
31
.travis.yml
31
.travis.yml
|
@ -13,14 +13,11 @@ addons:
|
||||||
- slapd
|
- slapd
|
||||||
- zookeeperd
|
- zookeeperd
|
||||||
- libzookeeper-mt-dev
|
- libzookeeper-mt-dev
|
||||||
- rabbitmq-server
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- MIN_PHP=7.2.5
|
- MIN_PHP=7.2.5
|
||||||
- SYMFONY_PROCESS_PHP_TEST_BINARY=~/.phpenv/shims/php
|
- SYMFONY_PROCESS_PHP_TEST_BINARY=~/.phpenv/shims/php
|
||||||
- MESSENGER_AMQP_DSN=amqp://localhost/%2f/messages
|
|
||||||
- MESSENGER_REDIS_DSN=redis://127.0.0.1:7006/messages
|
|
||||||
- SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1
|
- SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
@ -39,13 +36,6 @@ cache:
|
||||||
- php-$MIN_PHP
|
- php-$MIN_PHP
|
||||||
- ~/php-ext
|
- ~/php-ext
|
||||||
|
|
||||||
services:
|
|
||||||
- memcached
|
|
||||||
- mongodb
|
|
||||||
- redis-server
|
|
||||||
- rabbitmq
|
|
||||||
- docker
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- |
|
- |
|
||||||
# Enable Sury ppa
|
# Enable Sury ppa
|
||||||
|
@ -56,12 +46,6 @@ before_install:
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install -y librabbitmq-dev libsodium-dev
|
sudo apt install -y librabbitmq-dev libsodium-dev
|
||||||
|
|
||||||
- |
|
|
||||||
# Start Redis cluster
|
|
||||||
docker pull grokzen/redis-cluster:5.0.4
|
|
||||||
docker run -d -p 7000:7000 -p 7001:7001 -p 7002:7002 -p 7003:7003 -p 7004:7004 -p 7005:7005 -p 7006:7006 -p 7007:7007 -e "STANDALONE=true" --name redis-cluster grokzen/redis-cluster:5.0.4
|
|
||||||
export REDIS_CLUSTER_HOSTS='localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005'
|
|
||||||
|
|
||||||
- |
|
- |
|
||||||
# General configuration
|
# General configuration
|
||||||
set -e
|
set -e
|
||||||
|
@ -141,12 +125,6 @@ before_install:
|
||||||
(cd php-$MIN_PHP && ./configure --enable-sigchild --enable-pcntl && make -j2)
|
(cd php-$MIN_PHP && ./configure --enable-sigchild --enable-pcntl && make -j2)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- |
|
|
||||||
# Install vulcain
|
|
||||||
wget https://github.com/symfony/binary-utils/releases/download/v0.1/vulcain_0.1.3_Linux_x86_64.tar.gz -O - | tar xz
|
|
||||||
sudo mv vulcain /usr/local/bin
|
|
||||||
docker pull php:7.3-alpine
|
|
||||||
|
|
||||||
- |
|
- |
|
||||||
# php.ini configuration
|
# php.ini configuration
|
||||||
for PHP in $TRAVIS_PHP_VERSION $php_extra; do
|
for PHP in $TRAVIS_PHP_VERSION $php_extra; do
|
||||||
|
@ -268,15 +246,6 @@ install:
|
||||||
export PHP=$1
|
export PHP=$1
|
||||||
phpenv global $PHP
|
phpenv global $PHP
|
||||||
|
|
||||||
if [[ !$deps && $PHP = 7.2 ]]; then
|
|
||||||
phpenv global $PHP
|
|
||||||
tfold 'composer update' $COMPOSER_UP
|
|
||||||
[ -d .phpunit ] && mv .phpunit .phpunit.bak
|
|
||||||
tfold src/Symfony/Component/HttpClient.h2push "docker run -it --rm -v $(pwd):/app -v $(phpenv which composer):/usr/local/bin/composer -v /usr/local/bin/vulcain:/usr/local/bin/vulcain -w /app php:7.3-alpine ./phpunit src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push"
|
|
||||||
sudo rm .phpunit -rf
|
|
||||||
[ -d .phpunit.bak ] && mv .phpunit.bak .phpunit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $PHP != 7.4* && $PHP != $TRAVIS_PHP_VERSION && $TRAVIS_PULL_REQUEST != false ]]; then
|
if [[ $PHP != 7.4* && $PHP != $TRAVIS_PHP_VERSION && $TRAVIS_PULL_REQUEST != false ]]; then
|
||||||
echo -e "\\n\\e[33;1mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"
|
echo -e "\\n\\e[33;1mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"
|
||||||
return
|
return
|
||||||
|
|
|
@ -7,6 +7,56 @@ in 4.4 minor versions.
|
||||||
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
|
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
|
||||||
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.4.0...v4.4.1
|
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.4.0...v4.4.1
|
||||||
|
|
||||||
|
* 4.4.8 (2020-04-28)
|
||||||
|
|
||||||
|
* bug #36536 [Cache] Allow invalidateTags calls to be traced by data collector (l-vo)
|
||||||
|
* bug #36566 [PhpUnitBridge] Use COMPOSER_BINARY env var if available (fancyweb)
|
||||||
|
* bug #36560 [YAML] escape DEL(\x7f) (sdkawata)
|
||||||
|
* bug #36539 [PhpUnitBridge] fix compatibility with phpunit 9 (garak)
|
||||||
|
* bug #36555 [Cache] skip APCu in chains when the backend is disabled (nicolas-grekas)
|
||||||
|
* bug #36523 [Form] apply automatically step=1 for datetime-local input (ottaviano)
|
||||||
|
* bug #36519 [FrameworkBundle] debug:autowiring: Fix wrong display when using class_alias (weaverryan)
|
||||||
|
* bug #36454 [DependencyInjection][ServiceSubscriber] Support late aliases (fancyweb)
|
||||||
|
* bug #36498 [Security/Core] fix escape for username in LdapBindAuthenticationProvider.php (stoccc)
|
||||||
|
* bug #36506 [FrameworkBundle] Fix session.attribute_bag service definition (fancyweb)
|
||||||
|
* bug #36500 [Routing][PrefixTrait] Add the _locale requirement (fancyweb)
|
||||||
|
* bug #36457 [Cache] CacheItem with tag is never a hit after expired (alexander-schranz, nicolas-grekas)
|
||||||
|
* bug #36490 [HttpFoundation] workaround PHP bug in the session module (nicolas-grekas)
|
||||||
|
* bug #36483 [SecurityBundle] fix accepting env vars in remember-me configurations (zek)
|
||||||
|
* bug #36343 [Form] Fixed handling groups sequence validation (HeahDude)
|
||||||
|
* bug #36460 [Cache] Avoid memory leak in TraceableAdapter::reset() (lyrixx)
|
||||||
|
* bug #36467 Mailer from sender fixes (fabpot)
|
||||||
|
* bug #36408 [PhpUnitBridge] add PolyfillTestCaseTrait::expectExceptionMessageMatches to provide FC with recent phpunit versions (soyuka)
|
||||||
|
* bug #36447 Remove return type for Twig function workflow_metadata() (gisostallenberg)
|
||||||
|
* bug #36449 [Messenger] Make sure redis transports are initialized correctly (Seldaek)
|
||||||
|
* bug #36411 [Form] RepeatedType should always have inner types mapped (biozshock)
|
||||||
|
* bug #36441 [DI] fix loading defaults when using the PHP-DSL (nicolas-grekas)
|
||||||
|
* bug #36434 [HttpKernel] silence E_NOTICE triggered since PHP 7.4 (xabbuh)
|
||||||
|
* bug #36365 [Validator] Fixed default group for nested composite constraints (HeahDude)
|
||||||
|
* bug #36422 [HttpClient] fix HTTP/2 support on non-SSL connections - CurlHttpClient only (nicolas-grekas)
|
||||||
|
* bug #36417 Force ping after transport exception (oesteve)
|
||||||
|
* bug #35591 [Validator] do not merge constraints within interfaces (greedyivan)
|
||||||
|
* bug #36377 [HttpClient] Fix scoped client without query option configuration (X-Coder264)
|
||||||
|
* bug #36387 [DI] fix detecting short service syntax in yaml (nicolas-grekas)
|
||||||
|
* bug #36392 [DI] add missing property declarations in InlineServiceConfigurator (nicolas-grekas)
|
||||||
|
* bug #36400 Allowing empty secrets to be set (weaverryan)
|
||||||
|
* bug #36380 [Process] Fixed input/output error on PHP 7.4 (mbardelmeijer)
|
||||||
|
* bug #36376 [Workflow] Use a strict comparison when retrieving raw marking in MarkingStore (lyrixx)
|
||||||
|
* bug #36375 [Workflow] Use a strict comparison when retrieving raw marking in MarkingStore (lyrixx)
|
||||||
|
* bug #36305 [PropertyInfo][ReflectionExtractor] Check the array mutator prefixes last when the property is singular (fancyweb)
|
||||||
|
* bug #35656 [HttpFoundation] Fixed session migration with custom cookie lifetime (Guite)
|
||||||
|
* bug #36342 [HttpKernel][FrameworkBundle] fix compat with Debug component (nicolas-grekas)
|
||||||
|
* bug #36315 [WebProfilerBundle] Support for Content Security Policy style-src-elem and script-src-elem in WebProfiler (ampaze)
|
||||||
|
* bug #36286 [Validator] Allow URL-encoded special characters in basic auth part of URLs (cweiske)
|
||||||
|
* bug #36335 [Security] Track session usage whenever a new token is set (wouterj)
|
||||||
|
* bug #36332 [Serializer] Fix unitialized properties (from PHP 7.4.2) when serializing context for the cache key (alanpoulain)
|
||||||
|
* bug #36337 [MonologBridge] Fix $level type (fancyweb)
|
||||||
|
* bug #36223 [Security][Http][SwitchUserListener] Ignore all non existent username protection errors (fancyweb)
|
||||||
|
* bug #36239 [HttpKernel][LoggerDataCollector] Prevent keys collisions in the sanitized logs processing (fancyweb)
|
||||||
|
* bug #36245 [Validator] Fixed calling getters before resolving groups (HeahDude)
|
||||||
|
* bug #36265 Fix the reporting of deprecations in twig:lint (stof)
|
||||||
|
* bug #36283 [Security] forward multiple attributes voting flag (xabbuh)
|
||||||
|
|
||||||
* 4.4.7 (2020-03-30)
|
* 4.4.7 (2020-03-30)
|
||||||
|
|
||||||
* security #cve-2020-5255 [HttpFoundation] Do not set the default Content-Type based on the Accept header (yceruto)
|
* security #cve-2020-5255 [HttpFoundation] Do not set the default Content-Type based on the Accept header (yceruto)
|
||||||
|
|
|
@ -318,7 +318,14 @@ EOF
|
||||||
{
|
{
|
||||||
$filteredCatalogue = new MessageCatalogue($catalogue->getLocale());
|
$filteredCatalogue = new MessageCatalogue($catalogue->getLocale());
|
||||||
|
|
||||||
if ($messages = $catalogue->all($domain)) {
|
// extract intl-icu messages only
|
||||||
|
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||||
|
if ($intlMessages = $catalogue->all($intlDomain)) {
|
||||||
|
$filteredCatalogue->add($intlMessages, $intlDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract all messages and subtract intl-icu messages
|
||||||
|
if ($messages = array_diff($catalogue->all($domain), $intlMessages)) {
|
||||||
$filteredCatalogue->add($messages, $domain);
|
$filteredCatalogue->add($messages, $domain);
|
||||||
}
|
}
|
||||||
foreach ($catalogue->getResources() as $resource) {
|
foreach ($catalogue->getResources() as $resource) {
|
||||||
|
|
|
@ -26,9 +26,12 @@ class CachePoolsTest extends AbstractWebTestCase
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires extension redis
|
* @requires extension redis
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
public function testRedisCachePools()
|
public function testRedisCachePools()
|
||||||
{
|
{
|
||||||
|
$this->skipIfRedisUnavailable();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->doTestCachePools(['root_config' => 'redis_config.yml', 'environment' => 'redis_cache'], RedisAdapter::class);
|
$this->doTestCachePools(['root_config' => 'redis_config.yml', 'environment' => 'redis_cache'], RedisAdapter::class);
|
||||||
} catch (\PHPUnit\Framework\Error\Warning $e) {
|
} catch (\PHPUnit\Framework\Error\Warning $e) {
|
||||||
|
@ -51,9 +54,12 @@ class CachePoolsTest extends AbstractWebTestCase
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires extension redis
|
* @requires extension redis
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
public function testRedisCustomCachePools()
|
public function testRedisCustomCachePools()
|
||||||
{
|
{
|
||||||
|
$this->skipIfRedisUnavailable();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->doTestCachePools(['root_config' => 'redis_custom_config.yml', 'environment' => 'custom_redis_cache'], RedisAdapter::class);
|
$this->doTestCachePools(['root_config' => 'redis_custom_config.yml', 'environment' => 'custom_redis_cache'], RedisAdapter::class);
|
||||||
} catch (\PHPUnit\Framework\Error\Warning $e) {
|
} catch (\PHPUnit\Framework\Error\Warning $e) {
|
||||||
|
@ -121,4 +127,13 @@ class CachePoolsTest extends AbstractWebTestCase
|
||||||
{
|
{
|
||||||
return parent::createKernel(['test_case' => 'CachePools'] + $options);
|
return parent::createKernel(['test_case' => 'CachePools'] + $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function skipIfRedisUnavailable()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
(new \Redis())->connect(getenv('REDIS_HOST'));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,12 +129,11 @@ class ContentSecurityPolicyHandler
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isset($headers[$header][$type])) {
|
if (!isset($headers[$header][$type])) {
|
||||||
if (isset($headers[$header]['default-src'])) {
|
if (null === $fallback = $this->getDirectiveFallback($directives, $type)) {
|
||||||
$headers[$header][$type] = $headers[$header]['default-src'];
|
|
||||||
} else {
|
|
||||||
// If there is no script-src/style-src and no default-src, no additional rules required.
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$headers[$header][$type] = $fallback;
|
||||||
}
|
}
|
||||||
$ruleIsSet = true;
|
$ruleIsSet = true;
|
||||||
if (!\in_array('\'unsafe-inline\'', $headers[$header][$type], true)) {
|
if (!\in_array('\'unsafe-inline\'', $headers[$header][$type], true)) {
|
||||||
|
@ -199,9 +198,7 @@ class ContentSecurityPolicyHandler
|
||||||
{
|
{
|
||||||
if (isset($directivesSet[$type])) {
|
if (isset($directivesSet[$type])) {
|
||||||
$directives = $directivesSet[$type];
|
$directives = $directivesSet[$type];
|
||||||
} elseif (isset($directivesSet['default-src'])) {
|
} elseif (null === $directives = $this->getDirectiveFallback($directivesSet, $type)) {
|
||||||
$directives = $directivesSet['default-src'];
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +222,16 @@ class ContentSecurityPolicyHandler
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDirectiveFallback(array $directiveSet, $type)
|
||||||
|
{
|
||||||
|
if (\in_array($type, ['script-src-elem', 'style-src-elem'], true) || !isset($directiveSet['default-src'])) {
|
||||||
|
// Let the browser fallback on it's own
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $directiveSet['default-src'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the Content-Security-Policy headers (either X-Content-Security-Policy or Content-Security-Policy) from
|
* Retrieves the Content-Security-Policy headers (either X-Content-Security-Policy or Content-Security-Policy) from
|
||||||
* a response.
|
* a response.
|
||||||
|
|
|
@ -131,7 +131,14 @@ class ContentSecurityPolicyHandlerTest extends TestCase
|
||||||
['csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce],
|
['csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce],
|
||||||
$this->createRequest(),
|
$this->createRequest(),
|
||||||
$this->createResponse(['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'']),
|
$this->createResponse(['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'']),
|
||||||
['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src-elem \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src-elem \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null],
|
['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; style-src \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; style-src \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
$nonce,
|
||||||
|
['csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce],
|
||||||
|
$this->createRequest(),
|
||||||
|
$this->createResponse(['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\'; style-src \'self\' \'unsafe-inline\'; style-src-elem \'self\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\'; style-src \'self\' \'unsafe-inline\'; style-src-elem \'self\'']),
|
||||||
|
['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'self\' \'unsafe-inline\'; style-src-elem \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'self\' \'unsafe-inline\'; style-src-elem \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
$nonce,
|
$nonce,
|
||||||
|
|
|
@ -14,8 +14,8 @@ namespace Symfony\Component\Cache\Adapter;
|
||||||
use Predis\Connection\Aggregate\ClusterInterface;
|
use Predis\Connection\Aggregate\ClusterInterface;
|
||||||
use Predis\Connection\Aggregate\PredisCluster;
|
use Predis\Connection\Aggregate\PredisCluster;
|
||||||
use Predis\Response\Status;
|
use Predis\Response\Status;
|
||||||
use Symfony\Component\Cache\CacheItem;
|
|
||||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||||
|
use Symfony\Component\Cache\Exception\LogicException;
|
||||||
use Symfony\Component\Cache\Marshaller\DeflateMarshaller;
|
use Symfony\Component\Cache\Marshaller\DeflateMarshaller;
|
||||||
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||||
use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
|
use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
|
||||||
|
@ -95,9 +95,7 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter
|
||||||
{
|
{
|
||||||
$eviction = $this->getRedisEvictionPolicy();
|
$eviction = $this->getRedisEvictionPolicy();
|
||||||
if ('noeviction' !== $eviction && 0 !== strpos($eviction, 'volatile-')) {
|
if ('noeviction' !== $eviction && 0 !== strpos($eviction, 'volatile-')) {
|
||||||
CacheItem::log($this->logger, sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies', $eviction));
|
throw new LogicException(sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction));
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// serialize values
|
// serialize values
|
||||||
|
|
|
@ -34,9 +34,10 @@ abstract class AbstractRedisAdapterTest extends AdapterTestCase
|
||||||
if (!\extension_loaded('redis')) {
|
if (!\extension_loaded('redis')) {
|
||||||
self::markTestSkipped('Extension redis required.');
|
self::markTestSkipped('Extension redis required.');
|
||||||
}
|
}
|
||||||
if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) {
|
try {
|
||||||
$e = error_get_last();
|
(new \Redis())->connect(getenv('REDIS_HOST'));
|
||||||
self::markTestSkipped($e['message']);
|
} catch (\Exception $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,9 @@ use Psr\Cache\CacheItemPoolInterface;
|
||||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
||||||
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
|
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class MemcachedAdapterTest extends AdapterTestCase
|
class MemcachedAdapterTest extends AdapterTestCase
|
||||||
{
|
{
|
||||||
protected $skippedTests = [
|
protected $skippedTests = [
|
||||||
|
|
|
@ -14,6 +14,9 @@ namespace Symfony\Component\Cache\Tests\Adapter;
|
||||||
use Predis\Connection\StreamConnection;
|
use Predis\Connection\StreamConnection;
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class PredisAdapterTest extends AbstractRedisAdapterTest
|
class PredisAdapterTest extends AbstractRedisAdapterTest
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
namespace Symfony\Component\Cache\Tests\Adapter;
|
namespace Symfony\Component\Cache\Tests\Adapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class PredisClusterAdapterTest extends AbstractRedisAdapterTest
|
class PredisClusterAdapterTest extends AbstractRedisAdapterTest
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
|
|
|
@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Adapter;
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class PredisRedisClusterAdapterTest extends AbstractRedisAdapterTest
|
class PredisRedisClusterAdapterTest extends AbstractRedisAdapterTest
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
|
|
|
@ -15,6 +15,9 @@ use Psr\Cache\CacheItemPoolInterface;
|
||||||
use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
||||||
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class PredisTagAwareAdapterTest extends PredisAdapterTest
|
class PredisTagAwareAdapterTest extends PredisAdapterTest
|
||||||
{
|
{
|
||||||
use TagAwareTestTrait;
|
use TagAwareTestTrait;
|
||||||
|
|
|
@ -15,6 +15,9 @@ use Psr\Cache\CacheItemPoolInterface;
|
||||||
use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
||||||
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class PredisTagAwareClusterAdapterTest extends PredisClusterAdapterTest
|
class PredisTagAwareClusterAdapterTest extends PredisClusterAdapterTest
|
||||||
{
|
{
|
||||||
use TagAwareTestTrait;
|
use TagAwareTestTrait;
|
||||||
|
|
|
@ -14,6 +14,9 @@ namespace Symfony\Component\Cache\Tests\Adapter;
|
||||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisAdapterSentinelTest extends AbstractRedisAdapterTest
|
class RedisAdapterSentinelTest extends AbstractRedisAdapterTest
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
|
|
|
@ -16,6 +16,9 @@ use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||||
use Symfony\Component\Cache\Traits\RedisProxy;
|
use Symfony\Component\Cache\Traits\RedisProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisAdapterTest extends AbstractRedisAdapterTest
|
class RedisAdapterTest extends AbstractRedisAdapterTest
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
namespace Symfony\Component\Cache\Tests\Adapter;
|
namespace Symfony\Component\Cache\Tests\Adapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisArrayAdapterTest extends AbstractRedisAdapterTest
|
class RedisArrayAdapterTest extends AbstractRedisAdapterTest
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
|
|
|
@ -16,6 +16,9 @@ use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||||
use Symfony\Component\Cache\Traits\RedisClusterProxy;
|
use Symfony\Component\Cache\Traits\RedisClusterProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisClusterAdapterTest extends AbstractRedisAdapterTest
|
class RedisClusterAdapterTest extends AbstractRedisAdapterTest
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
|
|
|
@ -16,6 +16,9 @@ use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
||||||
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
||||||
use Symfony\Component\Cache\Traits\RedisProxy;
|
use Symfony\Component\Cache\Traits\RedisProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisTagAwareAdapterTest extends RedisAdapterTest
|
class RedisTagAwareAdapterTest extends RedisAdapterTest
|
||||||
{
|
{
|
||||||
use TagAwareTestTrait;
|
use TagAwareTestTrait;
|
||||||
|
|
|
@ -15,6 +15,9 @@ use Psr\Cache\CacheItemPoolInterface;
|
||||||
use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
||||||
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisTagAwareArrayAdapterTest extends RedisArrayAdapterTest
|
class RedisTagAwareArrayAdapterTest extends RedisArrayAdapterTest
|
||||||
{
|
{
|
||||||
use TagAwareTestTrait;
|
use TagAwareTestTrait;
|
||||||
|
|
|
@ -16,6 +16,9 @@ use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
||||||
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait;
|
||||||
use Symfony\Component\Cache\Traits\RedisClusterProxy;
|
use Symfony\Component\Cache\Traits\RedisClusterProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisTagAwareClusterAdapterTest extends RedisClusterAdapterTest
|
class RedisTagAwareClusterAdapterTest extends RedisClusterAdapterTest
|
||||||
{
|
{
|
||||||
use TagAwareTestTrait;
|
use TagAwareTestTrait;
|
||||||
|
|
|
@ -435,7 +435,7 @@ class QuestionHelper extends Helper
|
||||||
|
|
||||||
if (false !== $shell = $this->getShell()) {
|
if (false !== $shell = $this->getShell()) {
|
||||||
$readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
|
$readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
|
||||||
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
|
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword' 2> /dev/null", $shell, $readCmd);
|
||||||
$sCommand = shell_exec($command);
|
$sCommand = shell_exec($command);
|
||||||
$value = $trimmable ? rtrim($sCommand) : $sCommand;
|
$value = $trimmable ? rtrim($sCommand) : $sCommand;
|
||||||
$output->writeln('');
|
$output->writeln('');
|
||||||
|
@ -459,6 +459,11 @@ class QuestionHelper extends Helper
|
||||||
{
|
{
|
||||||
$error = null;
|
$error = null;
|
||||||
$attempts = $question->getMaxAttempts();
|
$attempts = $question->getMaxAttempts();
|
||||||
|
|
||||||
|
if (null === $attempts && !$this->isTty()) {
|
||||||
|
$attempts = 1;
|
||||||
|
}
|
||||||
|
|
||||||
while (null === $attempts || $attempts--) {
|
while (null === $attempts || $attempts--) {
|
||||||
if (null !== $error) {
|
if (null !== $error) {
|
||||||
$this->writeError($output, $error);
|
$this->writeError($output, $error);
|
||||||
|
@ -501,4 +506,19 @@ class QuestionHelper extends Helper
|
||||||
|
|
||||||
return self::$shell;
|
return self::$shell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function isTty(): bool
|
||||||
|
{
|
||||||
|
$inputStream = !$this->inputStream && \defined('STDIN') ? STDIN : $this->inputStream;
|
||||||
|
|
||||||
|
if (\function_exists('stream_isatty')) {
|
||||||
|
return stream_isatty($inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\function_exists('posix_isatty')) {
|
||||||
|
return posix_isatty($inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -726,6 +726,23 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
|
||||||
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question);
|
$dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAskThrowsExceptionFromValidatorEarlyWhenTtyIsMissing()
|
||||||
|
{
|
||||||
|
$this->expectException('Exception');
|
||||||
|
$this->expectExceptionMessage('Bar, not Foo');
|
||||||
|
|
||||||
|
$output = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')->getMock();
|
||||||
|
$output->expects($this->once())->method('writeln');
|
||||||
|
|
||||||
|
(new QuestionHelper())->ask(
|
||||||
|
$this->createStreamableInputInterfaceMock($this->getInputStream('Foo'), true),
|
||||||
|
$output,
|
||||||
|
(new Question('Q?'))->setHidden(true)->setValidator(function ($input) {
|
||||||
|
throw new \Exception("Bar, not $input");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testEmptyChoices()
|
public function testEmptyChoices()
|
||||||
{
|
{
|
||||||
$this->expectException('LogicException');
|
$this->expectException('LogicException');
|
||||||
|
|
|
@ -682,7 +682,7 @@ class YamlFileLoader extends FileLoader
|
||||||
try {
|
try {
|
||||||
$configuration = $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS);
|
$configuration = $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS);
|
||||||
} catch (ParseException $e) {
|
} catch (ParseException $e) {
|
||||||
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML: '.$e->getMessage(), $file), 0, $e);
|
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML', $file).': '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->validate($configuration, $file);
|
return $this->validate($configuration, $file);
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
$exceptionAsArray = $exception->toArray();
|
$exceptionAsArray = $exception->toArray();
|
||||||
$exceptionWithUserCode = [];
|
$exceptionWithUserCode = [];
|
||||||
$exceptionAsArrayCount = count($exceptionAsArray);
|
$exceptionAsArrayCount = count($exceptionAsArray);
|
||||||
$last = count($exceptionAsArray) - 1;
|
$last = $exceptionAsArrayCount - 1;
|
||||||
foreach ($exceptionAsArray as $i => $e) {
|
foreach ($exceptionAsArray as $i => $e) {
|
||||||
foreach ($e['trace'] as $trace) {
|
foreach ($e['trace'] as $trace) {
|
||||||
if ($trace['file'] && false === mb_strpos($trace['file'], '/vendor/') && false === mb_strpos($trace['file'], '/var/cache/') && $i < $last) {
|
if ($trace['file'] && false === mb_strpos($trace['file'], '/vendor/') && false === mb_strpos($trace['file'], '/var/cache/') && $i < $last) {
|
||||||
|
|
|
@ -14,10 +14,7 @@
|
||||||
|
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="Symfony ErrorHandler Component Test Suite">
|
<testsuite name="Symfony ErrorHandler Component Test Suite">
|
||||||
<directory>./Tests/</directory>
|
<directory suffix=".phpt">./Tests/</directory>
|
||||||
</testsuite>
|
|
||||||
<testsuite name="Symfony ErrorHandler Extension Test Suite">
|
|
||||||
<directory suffix=".phpt">./Resources/ext/tests/</directory>
|
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
|
|
|
@ -434,28 +434,19 @@ class Filesystem
|
||||||
$startPath = str_replace('\\', '/', $startPath);
|
$startPath = str_replace('\\', '/', $startPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stripDriveLetter = function ($path) {
|
$splitDriveLetter = function ($path) {
|
||||||
if (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) {
|
return (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0]))
|
||||||
return substr($path, 2);
|
? [substr($path, 2), strtoupper($path[0])]
|
||||||
}
|
: [$path, null];
|
||||||
|
|
||||||
return $path;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$endPath = $stripDriveLetter($endPath);
|
$splitPath = function ($path) {
|
||||||
$startPath = $stripDriveLetter($startPath);
|
|
||||||
|
|
||||||
// Split the paths into arrays
|
|
||||||
$startPathArr = explode('/', trim($startPath, '/'));
|
|
||||||
$endPathArr = explode('/', trim($endPath, '/'));
|
|
||||||
|
|
||||||
$normalizePathArray = function ($pathSegments) {
|
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
foreach ($pathSegments as $segment) {
|
foreach (explode('/', trim($path, '/')) as $segment) {
|
||||||
if ('..' === $segment) {
|
if ('..' === $segment) {
|
||||||
array_pop($result);
|
array_pop($result);
|
||||||
} elseif ('.' !== $segment) {
|
} elseif ('.' !== $segment && '' !== $segment) {
|
||||||
$result[] = $segment;
|
$result[] = $segment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,8 +454,16 @@ class Filesystem
|
||||||
return $result;
|
return $result;
|
||||||
};
|
};
|
||||||
|
|
||||||
$startPathArr = $normalizePathArray($startPathArr);
|
list($endPath, $endDriveLetter) = $splitDriveLetter($endPath);
|
||||||
$endPathArr = $normalizePathArray($endPathArr);
|
list($startPath, $startDriveLetter) = $splitDriveLetter($startPath);
|
||||||
|
|
||||||
|
$startPathArr = $splitPath($startPath);
|
||||||
|
$endPathArr = $splitPath($endPath);
|
||||||
|
|
||||||
|
if ($endDriveLetter && $startDriveLetter && $endDriveLetter != $startDriveLetter) {
|
||||||
|
// End path is on another drive, so no relative path exists
|
||||||
|
return $endDriveLetter.':/'.($endPathArr ? implode('/', $endPathArr).'/' : '');
|
||||||
|
}
|
||||||
|
|
||||||
// Find for which directory the common path stops
|
// Find for which directory the common path stops
|
||||||
$index = 0;
|
$index = 0;
|
||||||
|
|
|
@ -1151,10 +1151,14 @@ class FilesystemTest extends FilesystemTestCase
|
||||||
['/../aa/bb/cc', '/aa/dd/..', 'bb/cc/'],
|
['/../aa/bb/cc', '/aa/dd/..', 'bb/cc/'],
|
||||||
['/../../aa/../bb/cc', '/aa/dd/..', '../bb/cc/'],
|
['/../../aa/../bb/cc', '/aa/dd/..', '../bb/cc/'],
|
||||||
['C:/aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'],
|
['C:/aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'],
|
||||||
|
['C:/aa/bb/cc', 'c:/aa/dd/..', 'bb/cc/'],
|
||||||
['c:/aa/../bb/cc', 'c:/aa/dd/..', '../bb/cc/'],
|
['c:/aa/../bb/cc', 'c:/aa/dd/..', '../bb/cc/'],
|
||||||
['C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'],
|
['C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'],
|
||||||
['C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'],
|
['C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'],
|
||||||
['C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'],
|
['C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'],
|
||||||
|
['D:/', 'C:/aa/../bb/cc', 'D:/'],
|
||||||
|
['D:/aa/bb', 'C:/aa', 'D:/aa/bb/'],
|
||||||
|
['D:/../../aa/../bb/cc', 'C:/aa/dd/..', 'D:/bb/cc/'],
|
||||||
];
|
];
|
||||||
|
|
||||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||||
|
|
|
@ -62,7 +62,7 @@ class DependencyInjectionExtension implements FormExtensionInterface
|
||||||
$extensions = [];
|
$extensions = [];
|
||||||
|
|
||||||
if (isset($this->typeExtensionServices[$name])) {
|
if (isset($this->typeExtensionServices[$name])) {
|
||||||
foreach ($this->typeExtensionServices[$name] as $serviceId => $extension) {
|
foreach ($this->typeExtensionServices[$name] as $extension) {
|
||||||
$extensions[] = $extension;
|
$extensions[] = $extension;
|
||||||
|
|
||||||
$extendedTypes = [];
|
$extendedTypes = [];
|
||||||
|
@ -72,7 +72,7 @@ class DependencyInjectionExtension implements FormExtensionInterface
|
||||||
|
|
||||||
// validate the result of getExtendedTypes() to ensure it is consistent with the service definition
|
// validate the result of getExtendedTypes() to ensure it is consistent with the service definition
|
||||||
if (!\in_array($name, $extendedTypes, true)) {
|
if (!\in_array($name, $extendedTypes, true)) {
|
||||||
throw new InvalidArgumentException(sprintf('The extended type specified for the service "%s" does not match the actual extended type. Expected "%s", given "%s".', $serviceId, $name, implode(', ', $extendedTypes)));
|
throw new InvalidArgumentException(sprintf('The extended type "%s" specified for the type extension class "%s" does not match any of the actual extended types (["%s"]).', $name, \get_class($extension), implode('", "', $extendedTypes)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -958,7 +958,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
|
||||||
*
|
*
|
||||||
* @return FormInterface The child form
|
* @return FormInterface The child form
|
||||||
*
|
*
|
||||||
* @throws \OutOfBoundsException if the named child does not exist
|
* @throws OutOfBoundsException if the named child does not exist
|
||||||
*/
|
*/
|
||||||
public function offsetGet($name)
|
public function offsetGet($name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,7 +60,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
|
||||||
*
|
*
|
||||||
* @return self
|
* @return self
|
||||||
*
|
*
|
||||||
* @throws \OutOfBoundsException if the named child does not exist
|
* @throws Exception\OutOfBoundsException if the named child does not exist
|
||||||
*/
|
*/
|
||||||
public function get(string $name);
|
public function get(string $name);
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,8 @@ class DependencyInjectionExtensionTest extends TestCase
|
||||||
public function testThrowExceptionForInvalidExtendedType()
|
public function testThrowExceptionForInvalidExtendedType()
|
||||||
{
|
{
|
||||||
$this->expectException('Symfony\Component\Form\Exception\InvalidArgumentException');
|
$this->expectException('Symfony\Component\Form\Exception\InvalidArgumentException');
|
||||||
|
$this->expectExceptionMessage(sprintf('The extended type "unmatched" specified for the type extension class "%s" does not match any of the actual extended types (["test"]).', TestTypeExtension::class));
|
||||||
|
|
||||||
$extensions = [
|
$extensions = [
|
||||||
'unmatched' => new \ArrayIterator([new TestTypeExtension()]),
|
'unmatched' => new \ArrayIterator([new TestTypeExtension()]),
|
||||||
];
|
];
|
||||||
|
|
|
@ -44,6 +44,11 @@ abstract class AbstractRedisSessionHandlerTestCase extends TestCase
|
||||||
if (!\extension_loaded('redis')) {
|
if (!\extension_loaded('redis')) {
|
||||||
self::markTestSkipped('Extension redis required.');
|
self::markTestSkipped('Extension redis required.');
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
(new \Redis())->connect(getenv('REDIS_HOST'));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$host = getenv('REDIS_HOST') ?: 'localhost';
|
$host = getenv('REDIS_HOST') ?: 'localhost';
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,9 @@ namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
|
||||||
|
|
||||||
use Predis\Client;
|
use Predis\Client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class PredisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
class PredisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,6 +13,9 @@ namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
|
||||||
|
|
||||||
use Predis\Client;
|
use Predis\Client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class PredisSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
class PredisSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
|
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisArraySessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
class RedisArraySessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
|
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
class RedisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
|
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
class RedisSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
class RedisSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -294,30 +294,30 @@ class InflectorTest extends TestCase
|
||||||
/**
|
/**
|
||||||
* @dataProvider singularizeProvider
|
* @dataProvider singularizeProvider
|
||||||
*/
|
*/
|
||||||
public function testSingularize($plural, $singular)
|
public function testSingularize($plural, $expectedSingular)
|
||||||
{
|
{
|
||||||
$single = Inflector::singularize($plural);
|
$singular = Inflector::singularize($plural);
|
||||||
if (\is_string($singular) && \is_array($single)) {
|
if (\is_string($expectedSingular) && \is_array($singular)) {
|
||||||
$this->fail("--- Expected\n`string`: ".$singular."\n+++ Actual\n`array`: ".implode(', ', $single));
|
$this->fail("--- Expected\n`string`: ".$expectedSingular."\n+++ Actual\n`array`: ".implode(', ', $singular));
|
||||||
} elseif (\is_array($singular) && \is_string($single)) {
|
} elseif (\is_array($expectedSingular) && \is_string($singular)) {
|
||||||
$this->fail("--- Expected\n`array`: ".implode(', ', $singular)."\n+++ Actual\n`string`: ".$single);
|
$this->fail("--- Expected\n`array`: ".implode(', ', $expectedSingular)."\n+++ Actual\n`string`: ".$singular);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertEquals($singular, $single);
|
$this->assertEquals($expectedSingular, $singular);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider pluralizeProvider
|
* @dataProvider pluralizeProvider
|
||||||
*/
|
*/
|
||||||
public function testPluralize($plural, $singular)
|
public function testPluralize($singular, $expectedPlural)
|
||||||
{
|
{
|
||||||
$single = Inflector::pluralize($plural);
|
$plural = Inflector::pluralize($singular);
|
||||||
if (\is_string($singular) && \is_array($single)) {
|
if (\is_string($expectedPlural) && \is_array($plural)) {
|
||||||
$this->fail("--- Expected\n`string`: ".$singular."\n+++ Actual\n`array`: ".implode(', ', $single));
|
$this->fail("--- Expected\n`string`: ".$expectedPlural."\n+++ Actual\n`array`: ".implode(', ', $plural));
|
||||||
} elseif (\is_array($singular) && \is_string($single)) {
|
} elseif (\is_array($expectedPlural) && \is_string($plural)) {
|
||||||
$this->fail("--- Expected\n`array`: ".implode(', ', $singular)."\n+++ Actual\n`string`: ".$single);
|
$this->fail("--- Expected\n`array`: ".implode(', ', $expectedPlural)."\n+++ Actual\n`string`: ".$plural);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertEquals($singular, $single);
|
$this->assertEquals($expectedPlural, $plural);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ use Symfony\Component\Lock\Store\MemcachedStore;
|
||||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
*
|
*
|
||||||
* @requires extension memcached
|
* @requires extension memcached
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class MemcachedStoreTest extends AbstractStoreTest
|
class MemcachedStoreTest extends AbstractStoreTest
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Lock\Tests\Store;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class PredisStoreTest extends AbstractRedisStoreTest
|
class PredisStoreTest extends AbstractRedisStoreTest
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace Symfony\Component\Lock\Tests\Store;
|
||||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
*
|
*
|
||||||
* @requires extension redis
|
* @requires extension redis
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class RedisArrayStoreTest extends AbstractRedisStoreTest
|
class RedisArrayStoreTest extends AbstractRedisStoreTest
|
||||||
{
|
{
|
||||||
|
@ -23,9 +24,10 @@ class RedisArrayStoreTest extends AbstractRedisStoreTest
|
||||||
if (!class_exists('RedisArray')) {
|
if (!class_exists('RedisArray')) {
|
||||||
self::markTestSkipped('The RedisArray class is required.');
|
self::markTestSkipped('The RedisArray class is required.');
|
||||||
}
|
}
|
||||||
if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) {
|
try {
|
||||||
$e = error_get_last();
|
(new \Redis())->connect(getenv('REDIS_HOST'));
|
||||||
self::markTestSkipped($e['message']);
|
} catch (\Exception $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace Symfony\Component\Lock\Tests\Store;
|
||||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
*
|
*
|
||||||
* @requires extension redis
|
* @requires extension redis
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class RedisClusterStoreTest extends AbstractRedisStoreTest
|
class RedisClusterStoreTest extends AbstractRedisStoreTest
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,14 +17,16 @@ use Symfony\Component\Lock\Store\RedisStore;
|
||||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
*
|
*
|
||||||
* @requires extension redis
|
* @requires extension redis
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class RedisStoreTest extends AbstractRedisStoreTest
|
class RedisStoreTest extends AbstractRedisStoreTest
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
{
|
{
|
||||||
if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) {
|
try {
|
||||||
$e = error_get_last();
|
(new \Redis())->connect(getenv('REDIS_HOST'));
|
||||||
self::markTestSkipped($e['message']);
|
} catch (\Exception $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires extension amqp
|
* @requires extension amqp
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class AmqpExtIntegrationTest extends TestCase
|
class AmqpExtIntegrationTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,14 +17,14 @@ use Symfony\Component\Messenger\Transport\RedisExt\Connection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @requires extension redis >= 4.3.0
|
* @requires extension redis >= 4.3.0
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class ConnectionTest extends TestCase
|
class ConnectionTest extends TestCase
|
||||||
{
|
{
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
{
|
{
|
||||||
$redis = Connection::fromDsn('redis://localhost/queue');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$redis = Connection::fromDsn('redis://localhost/queue');
|
||||||
$redis->get();
|
$redis->get();
|
||||||
} catch (TransportException $e) {
|
} catch (TransportException $e) {
|
||||||
if (0 === strpos($e->getMessage(), 'ERR unknown command \'X')) {
|
if (0 === strpos($e->getMessage(), 'ERR unknown command \'X')) {
|
||||||
|
@ -32,6 +32,8 @@ class ConnectionTest extends TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
throw $e;
|
throw $e;
|
||||||
|
} catch (\RedisException $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ use Symfony\Component\Messenger\Transport\RedisExt\Connection;
|
||||||
/**
|
/**
|
||||||
* @requires extension redis
|
* @requires extension redis
|
||||||
* @group time-sensitive
|
* @group time-sensitive
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class RedisExtIntegrationTest extends TestCase
|
class RedisExtIntegrationTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -30,10 +31,14 @@ class RedisExtIntegrationTest extends TestCase
|
||||||
$this->markTestSkipped('The "MESSENGER_REDIS_DSN" environment variable is required.');
|
$this->markTestSkipped('The "MESSENGER_REDIS_DSN" environment variable is required.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redis = new \Redis();
|
try {
|
||||||
$this->connection = Connection::fromDsn(getenv('MESSENGER_REDIS_DSN'), [], $this->redis);
|
$this->redis = new \Redis();
|
||||||
$this->connection->cleanup();
|
$this->connection = Connection::fromDsn(getenv('MESSENGER_REDIS_DSN'), [], $this->redis);
|
||||||
$this->connection->setup();
|
$this->connection->cleanup();
|
||||||
|
$this->connection->setup();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConnectionSendAndGet()
|
public function testConnectionSendAndGet()
|
||||||
|
|
|
@ -31,12 +31,26 @@ class RedisTransportFactoryTest extends TestCase
|
||||||
$this->assertFalse($factory->supports('invalid-dsn', []));
|
$this->assertFalse($factory->supports('invalid-dsn', []));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
public function testCreateTransport()
|
public function testCreateTransport()
|
||||||
{
|
{
|
||||||
|
$this->skipIfRedisUnavailable();
|
||||||
|
|
||||||
$factory = new RedisTransportFactory();
|
$factory = new RedisTransportFactory();
|
||||||
$serializer = $this->getMockBuilder(SerializerInterface::class)->getMock();
|
$serializer = $this->getMockBuilder(SerializerInterface::class)->getMock();
|
||||||
$expectedTransport = new RedisTransport(Connection::fromDsn('redis://localhost', ['foo' => 'bar']), $serializer);
|
$expectedTransport = new RedisTransport(Connection::fromDsn('redis://'.getenv('REDIS_HOST'), ['foo' => 'bar']), $serializer);
|
||||||
|
|
||||||
$this->assertEquals($expectedTransport, $factory->createTransport('redis://localhost', ['foo' => 'bar'], $serializer));
|
$this->assertEquals($expectedTransport, $factory->createTransport('redis://'.getenv('REDIS_HOST'), ['foo' => 'bar'], $serializer));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function skipIfRedisUnavailable()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
(new \Redis())->connect(getenv('REDIS_HOST'));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ class YamlFileLoader extends FileLoader
|
||||||
try {
|
try {
|
||||||
$parsedConfig = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
|
$parsedConfig = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
|
||||||
} catch (ParseException $e) {
|
} catch (ParseException $e) {
|
||||||
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
|
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML', $path).': '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$collection = new RouteCollection();
|
$collection = new RouteCollection();
|
||||||
|
|
|
@ -151,6 +151,10 @@ class Serializer implements SerializerInterface, ContextAwareNormalizerInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\is_array($data) || $data instanceof \Traversable) {
|
if (\is_array($data) || $data instanceof \Traversable) {
|
||||||
|
if ($data instanceof \Countable && 0 === $data->count()) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
$normalized = [];
|
$normalized = [];
|
||||||
foreach ($data as $key => $val) {
|
foreach ($data as $key => $val) {
|
||||||
$normalized[$key] = $this->normalize($val, $format, $context);
|
$normalized[$key] = $this->normalize($val, $format, $context);
|
||||||
|
|
|
@ -25,6 +25,7 @@ use Symfony\Component\Serializer\Mapping\ClassMetadataInterface;
|
||||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||||
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
|
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
|
||||||
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
|
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
|
||||||
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
|
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
|
||||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
||||||
|
@ -488,6 +489,26 @@ class SerializerTest extends TestCase
|
||||||
(new Serializer())->normalize(tmpfile());
|
(new Serializer())->normalize(tmpfile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNormalizePreserveEmptyArrayObject()
|
||||||
|
{
|
||||||
|
$serializer = new Serializer(
|
||||||
|
[
|
||||||
|
new PropertyNormalizer(),
|
||||||
|
new ObjectNormalizer(),
|
||||||
|
new ArrayDenormalizer(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'json' => new JsonEncoder(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$object = [];
|
||||||
|
$object['foo'] = new \ArrayObject();
|
||||||
|
$object['bar'] = new \ArrayObject(['notempty']);
|
||||||
|
$object['baz'] = new \ArrayObject(['nested' => new \ArrayObject()]);
|
||||||
|
$this->assertEquals('{"foo":{},"bar":["notempty"],"baz":{"nested":{}}}', $serializer->serialize($object, 'json', [AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS => true]));
|
||||||
|
}
|
||||||
|
|
||||||
private function serializerWithClassDiscriminator()
|
private function serializerWithClassDiscriminator()
|
||||||
{
|
{
|
||||||
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
||||||
|
|
|
@ -42,7 +42,7 @@ class YamlFileLoader extends FileLoader
|
||||||
try {
|
try {
|
||||||
$messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT);
|
$messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT);
|
||||||
} catch (ParseException $e) {
|
} catch (ParseException $e) {
|
||||||
throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s".', $resource), 0, $e);
|
throw new InvalidResourceException(sprintf('The file "%s" does not contain valid YAML', $resource).': '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $messages && !\is_array($messages)) {
|
if (null !== $messages && !\is_array($messages)) {
|
||||||
|
|
|
@ -68,6 +68,11 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||||
public function all(string $domain = null)
|
public function all(string $domain = null)
|
||||||
{
|
{
|
||||||
if (null !== $domain) {
|
if (null !== $domain) {
|
||||||
|
// skip messages merge if intl-icu requested explicitly
|
||||||
|
if (false !== strpos($domain, self::INTL_DOMAIN_SUFFIX)) {
|
||||||
|
return $this->messages[$domain] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
return ($this->messages[$domain.self::INTL_DOMAIN_SUFFIX] ?? []) + ($this->messages[$domain] ?? []);
|
return ($this->messages[$domain.self::INTL_DOMAIN_SUFFIX] ?? []) + ($this->messages[$domain] ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,30 @@ class MessageCatalogueTest extends TestCase
|
||||||
$this->assertEquals($messages, $catalogue->all());
|
$this->assertEquals($messages, $catalogue->all());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAllIntICU()
|
||||||
|
{
|
||||||
|
$messages = [
|
||||||
|
'domain1+intl-icu' => ['foo' => 'bar'],
|
||||||
|
'domain2+intl-icu' => ['bar' => 'foo'],
|
||||||
|
'domain2' => ['biz' => 'biz'],
|
||||||
|
];
|
||||||
|
$catalogue = new MessageCatalogue('en', $messages);
|
||||||
|
|
||||||
|
// separated domains
|
||||||
|
$this->assertSame(['foo' => 'bar'], $catalogue->all('domain1+intl-icu'));
|
||||||
|
$this->assertSame(['bar' => 'foo'], $catalogue->all('domain2+intl-icu'));
|
||||||
|
|
||||||
|
// merged, intl-icu ignored
|
||||||
|
$this->assertSame(['bar' => 'foo', 'biz' => 'biz'], $catalogue->all('domain2'));
|
||||||
|
|
||||||
|
// intl-icu ignored
|
||||||
|
$messagesExpected = [
|
||||||
|
'domain1' => ['foo' => 'bar'],
|
||||||
|
'domain2' => ['bar' => 'foo', 'biz' => 'biz'],
|
||||||
|
];
|
||||||
|
$this->assertSame($messagesExpected, $catalogue->all());
|
||||||
|
}
|
||||||
|
|
||||||
public function testHas()
|
public function testHas()
|
||||||
{
|
{
|
||||||
$catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2+intl-icu' => ['bar' => 'bar']]);
|
$catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2+intl-icu' => ['bar' => 'bar']]);
|
||||||
|
|
|
@ -60,6 +60,9 @@ class EmailValidator extends ConstraintValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = (string) $value;
|
$value = (string) $value;
|
||||||
|
if ('' === $value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (null !== $constraint->normalizer) {
|
if (null !== $constraint->normalizer) {
|
||||||
$value = ($constraint->normalizer)($value);
|
$value = ($constraint->normalizer)($value);
|
||||||
|
|
|
@ -114,7 +114,7 @@ class YamlFileLoader extends FileLoader
|
||||||
try {
|
try {
|
||||||
$classes = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
|
$classes = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
|
||||||
} catch (ParseException $e) {
|
} catch (ParseException $e) {
|
||||||
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
|
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML', $path).': '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty file
|
// empty file
|
||||||
|
|
|
@ -352,7 +352,7 @@
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="91">
|
<trans-unit id="91">
|
||||||
<source>This value should be either negative or zero.</source>
|
<source>This value should be either negative or zero.</source>
|
||||||
<target>Ova vrednost bi trebala biti pozitivna ili nula.</target>
|
<target>Ova vrednost bi trebala biti negativna ili nula.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="92">
|
<trans-unit id="92">
|
||||||
<source>This value is not a valid timezone.</source>
|
<source>This value is not a valid timezone.</source>
|
||||||
|
|
|
@ -46,6 +46,13 @@ class EmailValidatorTest extends ConstraintValidatorTestCase
|
||||||
$this->assertNoViolation();
|
$this->assertNoViolation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testObjectEmptyStringIsValid()
|
||||||
|
{
|
||||||
|
$this->validator->validate(new EmptyEmailObject(), new Email());
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
}
|
||||||
|
|
||||||
public function testExpectsStringCompatibleType()
|
public function testExpectsStringCompatibleType()
|
||||||
{
|
{
|
||||||
$this->expectException('Symfony\Component\Validator\Exception\UnexpectedValueException');
|
$this->expectException('Symfony\Component\Validator\Exception\UnexpectedValueException');
|
||||||
|
@ -300,3 +307,11 @@ class EmailValidatorTest extends ConstraintValidatorTestCase
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EmptyEmailObject
|
||||||
|
{
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -53,6 +53,11 @@ class Entity extends EntityParent implements EntityInterfaceB
|
||||||
$this->internal = $internal;
|
$this->internal = $internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFirstName()
|
||||||
|
{
|
||||||
|
return $this->firstName;
|
||||||
|
}
|
||||||
|
|
||||||
public function getInternal()
|
public function getInternal()
|
||||||
{
|
{
|
||||||
return $this->internal.' from getter';
|
return $this->internal.' from getter';
|
||||||
|
@ -141,4 +146,9 @@ class Entity extends EntityParent implements EntityInterfaceB
|
||||||
{
|
{
|
||||||
$this->childB = $childB;
|
$this->childB = $childB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getReference()
|
||||||
|
{
|
||||||
|
return $this->reference;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
|
|
||||||
const REFERENCE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Reference';
|
const REFERENCE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Reference';
|
||||||
|
|
||||||
|
const LAZY_PROPERTY = 'Symfony\Component\Validator\Validator\LazyProperty';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var FakeMetadataFactory
|
* @var FakeMetadataFactory
|
||||||
*/
|
*/
|
||||||
|
@ -54,6 +56,7 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS);
|
$this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS);
|
||||||
$this->metadataFactory->addMetadata($this->metadata);
|
$this->metadataFactory->addMetadata($this->metadata);
|
||||||
$this->metadataFactory->addMetadata($this->referenceMetadata);
|
$this->metadataFactory->addMetadata($this->referenceMetadata);
|
||||||
|
$this->metadataFactory->addMetadata(new ClassMetadata(self::LAZY_PROPERTY));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function tearDown(): void
|
protected function tearDown(): void
|
||||||
|
@ -510,7 +513,10 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$this->validate($entity);
|
$this->validate($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testArrayReference()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testArrayReference($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = ['key' => new Reference()];
|
$entity->reference = ['key' => new Reference()];
|
||||||
|
@ -528,7 +534,7 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
$this->metadata->$constraintMethod('reference', new Valid());
|
||||||
$this->referenceMetadata->addConstraint(new Callback([
|
$this->referenceMetadata->addConstraint(new Callback([
|
||||||
'callback' => $callback,
|
'callback' => $callback,
|
||||||
'groups' => 'Group',
|
'groups' => 'Group',
|
||||||
|
@ -548,8 +554,10 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$this->assertNull($violations[0]->getCode());
|
$this->assertNull($violations[0]->getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/symfony/symfony/issues/6246
|
/**
|
||||||
public function testRecursiveArrayReference()
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testRecursiveArrayReference($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = [2 => ['key' => new Reference()]];
|
$entity->reference = [2 => ['key' => new Reference()]];
|
||||||
|
@ -567,7 +575,7 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
$this->metadata->$constraintMethod('reference', new Valid());
|
||||||
$this->referenceMetadata->addConstraint(new Callback([
|
$this->referenceMetadata->addConstraint(new Callback([
|
||||||
'callback' => $callback,
|
'callback' => $callback,
|
||||||
'groups' => 'Group',
|
'groups' => 'Group',
|
||||||
|
@ -611,7 +619,10 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$this->assertCount(0, $violations);
|
$this->assertCount(0, $violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testArrayTraversalCannotBeDisabled()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testArrayTraversalCannotBeDisabled($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = ['key' => new Reference()];
|
$entity->reference = ['key' => new Reference()];
|
||||||
|
@ -620,7 +631,7 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid([
|
$this->metadata->$constraintMethod('reference', new Valid([
|
||||||
'traverse' => false,
|
'traverse' => false,
|
||||||
]));
|
]));
|
||||||
$this->referenceMetadata->addConstraint(new Callback($callback));
|
$this->referenceMetadata->addConstraint(new Callback($callback));
|
||||||
|
@ -631,7 +642,10 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$this->assertCount(1, $violations);
|
$this->assertCount(1, $violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRecursiveArrayTraversalCannotBeDisabled()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testRecursiveArrayTraversalCannotBeDisabled($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = [2 => ['key' => new Reference()]];
|
$entity->reference = [2 => ['key' => new Reference()]];
|
||||||
|
@ -640,9 +654,10 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid([
|
$this->metadata->$constraintMethod('reference', new Valid([
|
||||||
'traverse' => false,
|
'traverse' => false,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
$this->referenceMetadata->addConstraint(new Callback($callback));
|
$this->referenceMetadata->addConstraint(new Callback($callback));
|
||||||
|
|
||||||
$violations = $this->validate($entity);
|
$violations = $this->validate($entity);
|
||||||
|
@ -651,12 +666,15 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$this->assertCount(1, $violations);
|
$this->assertCount(1, $violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIgnoreScalarsDuringArrayTraversal()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testIgnoreScalarsDuringArrayTraversal($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = ['string', 1234];
|
$entity->reference = ['string', 1234];
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
$this->metadata->$constraintMethod('reference', new Valid());
|
||||||
|
|
||||||
$violations = $this->validate($entity);
|
$violations = $this->validate($entity);
|
||||||
|
|
||||||
|
@ -664,12 +682,15 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
$this->assertCount(0, $violations);
|
$this->assertCount(0, $violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIgnoreNullDuringArrayTraversal()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testIgnoreNullDuringArrayTraversal($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = [null];
|
$entity->reference = [null];
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
$this->metadata->$constraintMethod('reference', new Valid());
|
||||||
|
|
||||||
$violations = $this->validate($entity);
|
$violations = $this->validate($entity);
|
||||||
|
|
||||||
|
@ -1218,6 +1239,14 @@ abstract class AbstractValidatorTest extends TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getConstraintMethods()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['addPropertyConstraint'],
|
||||||
|
['addGetterConstraint'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function getTestReplaceDefaultGroup()
|
public function getTestReplaceDefaultGroup()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -627,6 +627,10 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
||||||
// See validateClassNode()
|
// See validateClassNode()
|
||||||
$cascadedGroups = null !== $cascadedGroups && \count($cascadedGroups) > 0 ? $cascadedGroups : $groups;
|
$cascadedGroups = null !== $cascadedGroups && \count($cascadedGroups) > 0 ? $cascadedGroups : $groups;
|
||||||
|
|
||||||
|
if ($value instanceof LazyProperty) {
|
||||||
|
$value = $value->getPropertyValue();
|
||||||
|
}
|
||||||
|
|
||||||
if (\is_array($value)) {
|
if (\is_array($value)) {
|
||||||
// Arrays are always traversed, independent of the specified
|
// Arrays are always traversed, independent of the specified
|
||||||
// traversal strategy
|
// traversal strategy
|
||||||
|
|
|
@ -17,6 +17,7 @@ use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
|
||||||
/**
|
/**
|
||||||
* @author Nicolas Grekas <p@tchwork.com>
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
* @requires extension redis
|
* @requires extension redis
|
||||||
|
* @group integration
|
||||||
*/
|
*/
|
||||||
class RedisCasterTest extends TestCase
|
class RedisCasterTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -37,16 +38,18 @@ EODUMP;
|
||||||
|
|
||||||
public function testConnected()
|
public function testConnected()
|
||||||
{
|
{
|
||||||
|
$redisHost = getenv('REDIS_HOST');
|
||||||
$redis = new \Redis();
|
$redis = new \Redis();
|
||||||
if (!@$redis->connect('127.0.0.1')) {
|
try {
|
||||||
$e = error_get_last();
|
$redis->connect($redisHost);
|
||||||
self::markTestSkipped($e['message']);
|
} catch (\Exception $e) {
|
||||||
|
self::markTestSkipped($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$xCast = <<<'EODUMP'
|
$xCast = <<<EODUMP
|
||||||
Redis {%A
|
Redis {%A
|
||||||
isConnected: true
|
isConnected: true
|
||||||
host: "127.0.0.1"
|
host: "$redisHost"
|
||||||
port: 6379
|
port: 6379
|
||||||
auth: null
|
auth: null
|
||||||
mode: ATOMIC
|
mode: ATOMIC
|
||||||
|
|
|
@ -618,8 +618,14 @@ class Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
|
$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
|
||||||
|
$isItComment = $this->isCurrentLineComment();
|
||||||
|
|
||||||
while ($this->moveToNextLine()) {
|
while ($this->moveToNextLine()) {
|
||||||
|
if ($isItComment && !$isItUnindentedCollection) {
|
||||||
|
$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
|
||||||
|
$isItComment = $this->isCurrentLineComment();
|
||||||
|
}
|
||||||
|
|
||||||
$indent = $this->getCurrentLineIndentation();
|
$indent = $this->getCurrentLineIndentation();
|
||||||
|
|
||||||
if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
|
if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
|
||||||
|
|
|
@ -74,3 +74,17 @@ yaml: |
|
||||||
'foo #': baz
|
'foo #': baz
|
||||||
php: |
|
php: |
|
||||||
['foo #' => 'baz']
|
['foo #' => 'baz']
|
||||||
|
---
|
||||||
|
test: Comment before first item in unindented collection
|
||||||
|
brief: >
|
||||||
|
Comment directly before unindented collection is allowed
|
||||||
|
yaml: |
|
||||||
|
collection1:
|
||||||
|
# comment
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
collection2:
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
php: |
|
||||||
|
['collection1' => ['a', 'b'], 'collection2' => ['a', 'b']]
|
||||||
|
|
Reference in New Issue