diff --git a/.appveyor.yml b/.appveyor.yml index 4cdaf958bfd33..3cbe5480282b1 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,6 +12,7 @@ init: - SET SYMFONY_DEPRECATIONS_HELPER=strict - SET ANSICON=121x90 (121x90) - SET SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1 + - SET SYMFONY_DEPRECATIONS_HELPER=max[indirect]=170 - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f install: diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md deleted file mode 100644 index 16e2603b76a1d..0000000000000 --- a/.github/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,8 +0,0 @@ -# Code of Conduct - -This project follows a [Code of Conduct][code_of_conduct] in order to ensure an open and welcoming environment. -Please read the full text for understanding the accepted and unaccepted behavior. -Please read also the [reporting guidelines][guidelines], in case you encountered or witnessed any misbehavior. - -[code_of_conduct]: https://symfony.com/doc/current/contributing/code_of_conduct/index.html -[guidelines]: https://symfony.com/doc/current/contributing/code_of_conduct/reporting_guidelines.html diff --git a/.github/ISSUE_TEMPLATE/1_Bug_report.md b/.github/ISSUE_TEMPLATE/1_Bug_report.md deleted file mode 100644 index 0e34075718894..0000000000000 --- a/.github/ISSUE_TEMPLATE/1_Bug_report.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 🐛 Bug Report -about: Report errors and problems -labels: Bug - ---- - -**Symfony version(s) affected**: x.y.z - -**Description** - - -**How to reproduce** - - -**Possible Solution** - - -**Additional context** - diff --git a/.github/ISSUE_TEMPLATE/2_Feature_request.md b/.github/ISSUE_TEMPLATE/2_Feature_request.md deleted file mode 100644 index 335321e413607..0000000000000 --- a/.github/ISSUE_TEMPLATE/2_Feature_request.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: 🚀 Feature Request -about: RFC and ideas for new features and improvements - ---- - -**Description** - - -**Example** - diff --git a/.github/ISSUE_TEMPLATE/3_Support_question.md b/.github/ISSUE_TEMPLATE/3_Support_question.md deleted file mode 100644 index 9480710c15655..0000000000000 --- a/.github/ISSUE_TEMPLATE/3_Support_question.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: ⛔ Support Question -about: See https://symfony.com/support for questions about using Symfony and its components - ---- - -We use GitHub issues only to discuss about Symfony bugs and new features. For -this kind of questions about using Symfony or third-party bundles, please use -any of the support alternatives shown in https://symfony.com/support - -Thanks! diff --git a/.github/ISSUE_TEMPLATE/4_Documentation_issue.md b/.github/ISSUE_TEMPLATE/4_Documentation_issue.md deleted file mode 100644 index 0855c3c5f1e12..0000000000000 --- a/.github/ISSUE_TEMPLATE/4_Documentation_issue.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: ⛔ Documentation Issue -about: See https://github.com/symfony/symfony-docs/issues for documentation issues - ---- - -Symfony Documentation has its own dedicated repository. Please open your -documentation-related issue at https://github.com/symfony/symfony-docs/issues - -Thanks! diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2b27d887c2f74..d4182db630352 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | 5.x for features / 4.4, 5.1 or 5.2 for bug fixes +| Branch? | 5.x for features / 4.4 or 5.2 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no @@ -17,4 +17,5 @@ Additionally (see https://symfony.com/releases): - Bug fixes must be submitted against the lowest maintained branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too.) - Features and deprecations must be submitted against branch 5.x. + - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry --> diff --git a/.github/SECURITY.md b/.github/SECURITY.md deleted file mode 100644 index 60990950bf039..0000000000000 --- a/.github/SECURITY.md +++ /dev/null @@ -1,10 +0,0 @@ -Security Policy -=============== - -If you found any issues that might have security implications, -please send a report to security[at]symfony.com -DO NOT PUBLISH SECURITY REPORTS PUBLICLY. - -The full [Security Policy][1] is described in the official documentation. - - [1]: https://symfony.com/security diff --git a/.github/psalm/.gitignore b/.github/psalm/.gitignore new file mode 100644 index 0000000000000..d6b7ef32c8478 --- /dev/null +++ b/.github/psalm/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/.github/psalm/psalm.baseline.xml b/.github/psalm/psalm.baseline.xml new file mode 100644 index 0000000000000..f74693accd46f --- /dev/null +++ b/.github/psalm/psalm.baseline.xml @@ -0,0 +1,3 @@ + + + diff --git a/.github/workflows/intl-data-tests.yml b/.github/workflows/intl-data-tests.yml index 17e26dad0d1ec..0ca0322281448 100644 --- a/.github/workflows/intl-data-tests.yml +++ b/.github/workflows/intl-data-tests.yml @@ -1,47 +1,50 @@ name: Intl data tests on: - push: - paths: - - 'src/Symfony/Component/Intl/Resources/data/**' - pull_request: - paths: - - 'src/Symfony/Component/Intl/Resources/data/**' + push: + paths: + - 'src/Symfony/Component/Intl/Resources/data/**' + pull_request: + paths: + - 'src/Symfony/Component/Intl/Resources/data/**' -jobs: +defaults: + run: + shell: bash - tests: - name: Tests (intl-data) - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Define the ICU version - run: | - SYMFONY_ICU_VERSION=$(php -r 'require "src/Symfony/Component/Intl/Intl.php"; echo Symfony\Component\Intl\Intl::getIcuStubVersion();') - echo "SYMFONY_ICU_VERSION=$SYMFONY_ICU_VERSION" >> $GITHUB_ENV - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - coverage: "none" - extensions: "zip,intl-${{env.SYMFONY_ICU_VERSION}}" - ini-values: "memory_limit=-1" - php-version: "7.4" - - - 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: Report the ICU version - run: icu-config --version && php -i | grep 'ICU version' - - - name: Run intl-data tests - run: ./phpunit --group intl-data -v +jobs: + tests: + name: Tests (intl-data) + runs-on: Ubuntu-20.04 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Define the ICU version + run: | + SYMFONY_ICU_VERSION=$(php -r 'require "src/Symfony/Component/Intl/Intl.php"; echo Symfony\Component\Intl\Intl::getIcuStubVersion();') + echo "SYMFONY_ICU_VERSION=$SYMFONY_ICU_VERSION" >> $GITHUB_ENV + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + coverage: "none" + extensions: "zip,intl-${{env.SYMFONY_ICU_VERSION}}" + ini-values: "memory_limit=-1" + php-version: "7.4" + + - 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: Report the ICU version + run: icu-config --version && php -i | grep 'ICU version' + + - name: Run intl-data tests + run: ./phpunit --group intl-data -v diff --git a/.github/workflows/phpunit-bridge.yml b/.github/workflows/phpunit-bridge.yml index bdda65de1b6f5..b503ce48d8a17 100644 --- a/.github/workflows/phpunit-bridge.yml +++ b/.github/workflows/phpunit-bridge.yml @@ -1,28 +1,31 @@ name: PhpUnitBridge on: - push: - paths: - - 'src/Symfony/Bridge/PhpUnit/**' - pull_request: - paths: - - 'src/Symfony/Bridge/PhpUnit/**' + push: + paths: + - 'src/Symfony/Bridge/PhpUnit/**' + pull_request: + paths: + - 'src/Symfony/Bridge/PhpUnit/**' -jobs: +defaults: + run: + shell: bash - lint: - name: Lint - runs-on: ubuntu-latest +jobs: + lint: + name: Lint + runs-on: Ubuntu-20.04 - steps: - - name: Checkout - uses: actions/checkout@v2 + steps: + - name: Checkout + uses: actions/checkout@v2 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - coverage: "none" - php-version: "5.5" + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + coverage: "none" + php-version: "5.5" - - name: Lint - run: find ./src/Symfony/Bridge/PhpUnit -name '*.php' | grep -v -e /Tests/ -e ForV6 -e ForV7 -e ForV8 -e ForV9 -e ConstraintLogicTrait | parallel -j 4 php -l {} + - name: Lint + run: find ./src/Symfony/Bridge/PhpUnit -name '*.php' | grep -v -e /Tests/ -e ForV6 -e ForV7 -e ForV8 -e ForV9 -e ConstraintLogicTrait | parallel -j 4 php -l {} diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml new file mode 100644 index 0000000000000..4c15203380059 --- /dev/null +++ b/.github/workflows/psalm.yml @@ -0,0 +1,58 @@ +name: Static analysis + +on: + pull_request: ~ + +defaults: + run: + shell: bash + +jobs: + psalm: + name: Psalm + runs-on: Ubuntu-20.04 + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.0' + extensions: "json,memcached,mongodb,redis,xsl,ldap,dom" + ini-values: "memory_limit=-1" + coverage: none + + - name: Checkout target branch + uses: actions/checkout@v2 + with: + ref: ${{ github.base_ref }} + + - name: Checkout PR + uses: actions/checkout@v2 + + - name: Configure composer + run: | + COMPOSER_HOME="$(composer config home)" + ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" + echo "COMPOSER_ROOT_VERSION=$(grep -m1 SYMFONY_VERSION .travis.yml | grep -o '[0-9.x]*').x-dev" >> $GITHUB_ENV + + - name: Install Psalm + run: | + echo "::group::modify composer.json" + composer remove --no-update --no-interaction symfony/phpunit-bridge + composer require --no-update psalm/phar phpunit/phpunit php-http/discovery psr/event-dispatcher + echo "::endgroup::" + echo "::group::composer update" + composer update --no-progress --ansi + git checkout composer.json + echo "::endgroup::" + ./vendor/bin/psalm.phar --version + + - name: Generate Psalm baseline + run: | + git checkout -m ${{ github.base_ref }} + ./vendor/bin/psalm.phar --set-baseline=.github/psalm/psalm.baseline.xml --no-progress + git checkout -m FETCH_HEAD + + - name: Psalm + run: | + ./vendor/bin/psalm.phar --output-format=github --no-progress diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 96f4b8be0996b..d8e6586e5b4b7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,190 +1,193 @@ name: Tests on: - push: - pull_request: + push: + pull_request: -jobs: +defaults: + run: + shell: bash - integration: - name: Integration - runs-on: ubuntu-latest - - strategy: - matrix: - php: ['7.2', '7.4'] - - services: - postgres: - image: postgres:9.6-alpine - ports: - - 5432:5432 - env: - POSTGRES_PASSWORD: 'password' - ldap: - image: bitnami/openldap - ports: - - 3389:3389 - env: - LDAP_ADMIN_USERNAME: admin - LDAP_ADMIN_PASSWORD: symfony - LDAP_ROOT: dc=symfony,dc=com - LDAP_PORT_NUMBER: 3389 - LDAP_USERS: a - LDAP_PASSWORDS: a - 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 - env: - STANDALONE: 1 - redis-sentinel: - image: bitnami/redis-sentinel:6.0 - ports: - - 26379:26379 - env: - REDIS_MASTER_HOST: redis - REDIS_MASTER_SET: redis_sentinel - REDIS_SENTINEL_QUORUM: 1 - memcached: - image: memcached:1.6.5 - ports: - - 11211:11211 - rabbitmq: - image: rabbitmq:3.8.3 - ports: - - 5672:5672 - mongodb: - image: mongo - ports: - - 27017:27017 - couchbase: - image: couchbase:6.5.1 - ports: - - 8091:8091 - - 8092:8092 - - 8093:8093 - - 8094:8094 - - 11210:11210 - sqs: - image: asyncaws/testing-sqs - ports: - - 9494:9494 - zookeeper: - image: wurstmeister/zookeeper:3.4.6 - kafka: - image: wurstmeister/kafka:2.12-2.4.1 - ports: - - 9092:9092 - env: - KAFKA_AUTO_CREATE_TOPICS_ENABLE: false - KAFKA_CREATE_TOPICS: 'test-topic:1:1:compact' - KAFKA_ADVERTISED_HOST_NAME: localhost - KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' - KAFKA_ADVERTISED_PORT: 9092 - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Install system dependencies - run: | - echo "::group::apt-get update" - sudo apt-get update - echo "::endgroup::" - - echo "::group::install tools & libraries" - sudo apt-get install librdkafka-dev - echo "::endgroup::" - - - name: Configure Couchbase - run: | - curl -s -u 'username=Administrator&password=111111' -X POST http://localhost:8091/node/controller/setupServices -d 'services=kv%2Cn1ql%2Cindex%2Cfts' - curl -s -X POST http://localhost:8091/settings/web -d 'username=Administrator&password=111111&port=SAME' - curl -s -u Administrator:111111 -X POST http://localhost:8091/pools/default/buckets -d 'ramQuotaMB=100&bucketType=ephemeral&name=cache' - curl -s -u Administrator:111111 -X POST http://localhost:8091/pools/default -d 'memoryQuota=256' - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - coverage: "none" - extensions: "json,couchbase,memcached,mongodb,redis,rdkafka,xsl,ldap" - ini-values: "memory_limit=-1" - php-version: "${{ matrix.php }}" - tools: pecl - - - name: Display versions - run: | - php -r 'foreach (get_loaded_extensions() as $extension) echo $extension . " " . phpversion($extension) . PHP_EOL;' - php -i - - - name: Load fixtures - uses: docker://bitnami/openldap - with: - entrypoint: /bin/bash - args: -c "(/opt/bitnami/openldap/bin/ldapwhoami -h localhost:3389 -D cn=admin,dc=symfony,dc=com -w symfony||sleep 5) && /opt/bitnami/openldap/bin/ldapadd -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony -f src/Symfony/Component/Ldap/Tests/Fixtures/data/fixtures.ldif && /opt/bitnami/openldap/bin/ldapdelete -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony cn=a,ou=users,dc=symfony,dc=com" - - - name: Configure composer - run: | - COMPOSER_HOME="$(composer config home)" - composer self-update - ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" - echo "COMPOSER_ROOT_VERSION=$(grep -m1 SYMFONY_VERSION .travis.yml | grep -o '[0-9.x]*').x-dev" >> $GITHUB_ENV - - - 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 require --dev --no-update mongodb/mongodb:@stable - composer update --no-progress --ansi - echo "::endgroup::" - echo "::group::install phpunit" - ./phpunit install - echo "::endgroup::" - - - name: Run tests - run: ./phpunit --group integration -v - env: - REDIS_HOST: localhost - REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' - REDIS_SENTINEL_HOSTS: 'localhost:26379' - REDIS_SENTINEL_SERVICE: redis_sentinel - MESSENGER_REDIS_DSN: redis://127.0.0.1:7006/messages - MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages - MESSENGER_SQS_DSN: "sqs://localhost:9494/messages?sslmode=disable&poll_timeout=0.01" - MESSENGER_SQS_FIFO_QUEUE_DSN: "sqs://localhost:9494/messages.fifo?sslmode=disable&poll_timeout=0.01" - MEMCACHED_HOST: localhost - LDAP_HOST: localhost - LDAP_PORT: 3389 - MONGODB_HOST: localhost - KAFKA_BROKER: localhost:9092 - POSTGRES_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 -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 src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push - sudo rm -rf .phpunit - [ -d .phpunit.bak ] && mv .phpunit.bak .phpunit +jobs: + integration: + name: Integration + runs-on: Ubuntu-20.04 + + strategy: + matrix: + php: ['7.2', '7.4'] + + services: + postgres: + image: postgres:9.6-alpine + ports: + - 5432:5432 + env: + POSTGRES_PASSWORD: 'password' + ldap: + image: bitnami/openldap + ports: + - 3389:3389 + env: + LDAP_ADMIN_USERNAME: admin + LDAP_ADMIN_PASSWORD: symfony + LDAP_ROOT: dc=symfony,dc=com + LDAP_PORT_NUMBER: 3389 + LDAP_USERS: a + LDAP_PASSWORDS: a + 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 + env: + STANDALONE: 1 + redis-sentinel: + image: bitnami/redis-sentinel:6.0 + ports: + - 26379:26379 + env: + REDIS_MASTER_HOST: redis + REDIS_MASTER_SET: redis_sentinel + REDIS_SENTINEL_QUORUM: 1 + memcached: + image: memcached:1.6.5 + ports: + - 11211:11211 + rabbitmq: + image: rabbitmq:3.8.3 + ports: + - 5672:5672 + mongodb: + image: mongo + ports: + - 27017:27017 + couchbase: + image: couchbase:6.5.1 + ports: + - 8091:8091 + - 8092:8092 + - 8093:8093 + - 8094:8094 + - 11210:11210 + sqs: + image: asyncaws/testing-sqs + ports: + - 9494:9494 + zookeeper: + image: wurstmeister/zookeeper:3.4.6 + kafka: + image: wurstmeister/kafka:2.12-2.4.1 + ports: + - 9092:9092 + env: + KAFKA_AUTO_CREATE_TOPICS_ENABLE: false + KAFKA_CREATE_TOPICS: 'test-topic:1:1:compact' + KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1 + KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' + KAFKA_ADVERTISED_PORT: 9092 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install system dependencies + run: | + echo "::group::apt-get update" + sudo apt-get update + echo "::endgroup::" + + echo "::group::install tools & libraries" + sudo apt-get install librdkafka-dev + echo "::endgroup::" + + - name: Configure Couchbase + run: | + curl -s -u 'username=Administrator&password=111111' -X POST http://localhost:8091/node/controller/setupServices -d 'services=kv%2Cn1ql%2Cindex%2Cfts' + curl -s -X POST http://localhost:8091/settings/web -d 'username=Administrator&password=111111&port=SAME' + curl -s -u Administrator:111111 -X POST http://localhost:8091/pools/default/buckets -d 'ramQuotaMB=100&bucketType=ephemeral&name=cache' + curl -s -u Administrator:111111 -X POST http://localhost:8091/pools/default -d 'memoryQuota=256' + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + coverage: "none" + extensions: "json,couchbase,memcached,mongodb,redis,rdkafka,xsl,ldap" + ini-values: "memory_limit=-1" + php-version: "${{ matrix.php }}" + tools: pecl + + - name: Display versions + run: | + php -r 'foreach (get_loaded_extensions() as $extension) echo $extension . " " . phpversion($extension) . PHP_EOL;' + php -i + + - name: Load fixtures + uses: docker://bitnami/openldap + with: + entrypoint: /bin/bash + args: -c "(/opt/bitnami/openldap/bin/ldapwhoami -h localhost:3389 -D cn=admin,dc=symfony,dc=com -w symfony||sleep 5) && /opt/bitnami/openldap/bin/ldapadd -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony -f src/Symfony/Component/Ldap/Tests/Fixtures/data/fixtures.ldif && /opt/bitnami/openldap/bin/ldapdelete -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony cn=a,ou=users,dc=symfony,dc=com" + + - name: Configure composer + run: | + COMPOSER_HOME="$(composer config home)" + composer self-update + ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" + echo "COMPOSER_ROOT_VERSION=$(grep -m1 SYMFONY_VERSION .travis.yml | grep -o '[0-9.x]*').x-dev" >> $GITHUB_ENV + + - 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 require --dev --no-update mongodb/mongodb:@stable + composer update --no-progress --ansi + echo "::endgroup::" + echo "::group::install phpunit" + ./phpunit install + echo "::endgroup::" + + - name: Run tests + run: ./phpunit --group integration -v + env: + REDIS_HOST: localhost + REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' + REDIS_SENTINEL_HOSTS: 'localhost:26379' + REDIS_SENTINEL_SERVICE: redis_sentinel + MESSENGER_REDIS_DSN: redis://127.0.0.1:7006/messages + MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages + MESSENGER_SQS_DSN: "sqs://localhost:9494/messages?sslmode=disable&poll_timeout=0.01" + MESSENGER_SQS_FIFO_QUEUE_DSN: "sqs://localhost:9494/messages.fifo?sslmode=disable&poll_timeout=0.01" + MEMCACHED_HOST: localhost + LDAP_HOST: localhost + LDAP_PORT: 3389 + MONGODB_HOST: localhost + KAFKA_BROKER: 127.0.0.1:9092 + POSTGRES_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 -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 src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push + sudo rm -rf .phpunit + [ -d .phpunit.bak ] && mv .phpunit.bak .phpunit diff --git a/.travis.yml b/.travis.yml index 80c86ecdf7444..009143743f598 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,7 @@ before_install: export PHPUNIT_X="$PHPUNIT --exclude-group tty,benchmark,intl-data" export COMPOSER_UP='composer update --no-progress --ansi' export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) + export SYMFONY_DEPRECATIONS_HELPER=max[indirect]=170 nanoseconds () { local cmd="date" @@ -254,7 +255,7 @@ install: fi phpenv global $PHP rm vendor/composer/package-versions-deprecated -Rf - ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb ^1.9.0) + ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb) tfold 'composer update' $COMPOSER_UP tfold 'phpunit install' ./phpunit install if [[ $deps = high ]]; then diff --git a/CHANGELOG-5.2.md b/CHANGELOG-5.2.md index 7fe615b1fcca4..b77697fd01f15 100644 --- a/CHANGELOG-5.2.md +++ b/CHANGELOG-5.2.md @@ -7,6 +7,56 @@ in 5.2 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 between two versions, go to https://github.com/symfony/symfony/compare/v5.2.0...v5.2.1 +* 5.2.4 (2021-03-04) + + * bug #40336 [Messenger] Doctrine setup with migrations (Nyholm) + * bug #40318 [Translation] deal with indented heredoc/nowdoc tokens (xabbuh) + * bug #40350 [DependencyInjection] fix parsing calls of methods named "method" (xabbuh) + * bug #40316 [Serializer] zero parts can be omitted in date interval input (xabbuh) + * bug #40239 MockResponse total_time should not be simulated when provided (Pierrick VIGNAND) + * bug #40299 [Cache] Add server-commands support for Predis Replication Environments (DemigodCode) + * bug #40231 [HttpKernel] Configure `session.cookie_secure` earlier (tamcy) + * bug #40283 [Translation] Make `name` attribute optional in xliff2 (MarieMinasyan) + * bug #40286 [Security] #[CurrentUser] arguments should resolve to null for "anon." (chalasr) + * bug #40281 [FrameworkBundle] Allow x-forwarded-prefix trusted header in config (drupol) + * bug #39599 [Cache] Fix Redis TLS scheme `rediss` for Redis connection (misaert) + * bug #40244 [Routing] fix conflict with param named class in attribute (nlhommet) + * bug #40273 [Cache] fix setting items' metadata on commit() (nicolas-grekas) + * bug #40258 [Form] Ignoring invalid forms from delete_empty behavior in CollectionType (yceruto) + * bug #40246 [EventDispatcher] fix registering subscribers twice on edge-case (nicolas-grekas) + * bug #40162 [Intl] fix Locale::getFallback() throwing exception on long $locale (AmirHo3ein13) + * bug #40211 [Validator] fix taking error message from the correct violation (xabbuh) + * bug #40208 [PropertyInfo] fix resolving self to name of the analyzed class (xabbuh) + * bug #40209 [WebLink] Escape double quotes in attributes values (fancyweb) + * bug #40192 [Console] fix QuestionHelper::getHiddenResponse() not working with space in project directory name (Yendric) + * bug #40203 [String] Check if function exists before declaring it (Nyholm) + * bug #40175 [PropertyInfo]  use the right context for properties defined in traits (xabbuh) + * bug #40172 [Translation] Allow using dashes in locale when linting Xliff files (localheinz) + * bug #39671 [Worflow] Fixed GuardListener when using the new Security system (lyrixx) + * bug #40187 [Console] Fix PHP 8.1 null error for preg_match flag (kylekatarnls) + * bug #39659 [Form] keep valid submitted choices when additional choices are submitted (xabbuh) + * bug #40188 [HttpFoundation] Fix PHP 8.1 null values (kylekatarnls) + * bug #40167 [DependencyInjection] Definition::removeMethodCall should remove all matching calls (ruudk) + * bug #40160 [PropertyInfo] fix extracting mixed type-hinted property types (xabbuh) + * bug #40040 [Finder] Use a lazyIterator to close files descriptors when no longer used (jderusse) + * bug #40141 [RateLimiter] Fix sliding_window misbehaving with stale records (xesxen) + * bug #40135 [FrameworkBundle] Fix freshness checks with boolean parameters on routes (HypeMC) + * bug #40138 [FrameworkBundle] fix registering "annotations.cache" on the "container.hot_path" (nicolas-grekas) + * bug #40137 [Form] forward the label_html option to expanded choice fields (xabbuh) + * bug #40116 [FrameworkBundle][Translator] scan directories for translations sequentially (xabbuh) + * bug #40124 [Form] merge translation parameters with value configured for parent form (xabbuh) + * bug #40104 [HttpKernel] [Kernel] Silence failed deprecations logs writes (fancyweb) + * bug #40098 [DependencyInjection] fix tracking of changes to vendor/ dirs (nicolas-grekas) + * bug #39980 [Mailer][Mime] Update inline part names with newly generated ContentId (ddegentesh) + * bug #40043 [HttpFoundation] Setting `REQUEST_TIME_FLOAT` when constructing a Request object (ctasada) + * bug #40050 [FrameworkBundle][Translator] Fixed updating catalogue metadata from Intl domain (yceruto) + * bug #40080 Fix Request with DNS issue not retried (jderusse) + * bug #40089 [SecurityBundle] role_names variable instead of roles (wickedOne) + * bug #40042 [Doctrine] Restore priority for EventSubscribers (jderusse) + * bug #40066 [ErrorHandler] fix parsing return types in DebugClassLoader (nicolas-grekas) + * bug #40065 [ErrorHandler] fix handling messages with null bytes from anonymous classes (nicolas-grekas) + * bug #40067 [PhpUnitBridge] fix reporting deprecations when they come from DebugClassLoader (nicolas-grekas) + * 5.2.3 (2021-02-03) * bug #39954 [Mailer][Mime] Fix case-sensitive handling of header names (piku235) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5b8efba4073b3..b64aa797a5b14 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,8 +1,11 @@ CONTRIBUTORS ============ -Symfony is the result of the work of many people who made the code better -(see https://symfony.com/contributors for more information): +Symfony is the result of the work of many people who made the code better. + +The Symfony Connect username in parenthesis allows to get more information +about contributors (like https://connect.symfony.com/profile/fabpot). See +https://symfony.com/contributors for more information. - Fabien Potencier (fabpot) - Nicolas Grekas (nicolas-grekas) diff --git a/composer.json b/composer.json index e92efba50fae6..667c2dee04081 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,22 @@ "homepage": "https://symfony.com/contributors" } ], + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/cache-implementation": "1.0|2.0", + "psr/container-implementation": "1.0", + "psr/event-dispatcher-implementation": "1.0", + "psr/http-client-implementation": "1.0", + "psr/link-implementation": "1.0", + "psr/log-implementation": "1.0", + "psr/simple-cache-implementation": "1.0", + "symfony/cache-implementation": "1.0|2.0", + "symfony/event-dispatcher-implementation": "2.0", + "symfony/http-client-implementation": "2.2", + "symfony/service-implementation": "1.0|2.0", + "symfony/translation-implementation": "2.3" + }, "require": { "php": ">=7.2.5", "ext-xml": "*", @@ -22,7 +38,7 @@ "doctrine/event-manager": "~1.0", "doctrine/persistence": "^2", "twig/twig": "^2.13|^3.0.4", - "psr/cache": "~1.0", + "psr/cache": "^1.0|^2.0", "psr/container": "^1.0", "psr/event-dispatcher": "^1.0", "psr/link": "^1.0", @@ -154,6 +170,9 @@ "Symfony\\Bundle\\": "src/Symfony/Bundle/", "Symfony\\Component\\": "src/Symfony/Component/" }, + "files": [ + "src/Symfony/Component/String/Resources/functions.php" + ], "classmap": [ "src/Symfony/Component/Intl/Resources/stubs" ], @@ -163,7 +182,6 @@ }, "autoload-dev": { "files": [ - "src/Symfony/Component/String/Resources/functions.php", "src/Symfony/Component/VarDumper/Resources/functions/dump.php" ] }, diff --git a/phpunit b/phpunit index 9141d249d2695..cdd9af8352881 100755 --- a/phpunit +++ b/phpunit @@ -8,15 +8,13 @@ if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) { exit(1); } if (!getenv('SYMFONY_PHPUNIT_VERSION')) { - if (\PHP_VERSION_ID < 70200) { - putenv('SYMFONY_PHPUNIT_VERSION=7.5'); - } elseif (\PHP_VERSION_ID < 70300) { + if (\PHP_VERSION_ID < 70300) { putenv('SYMFONY_PHPUNIT_VERSION=8.5'); } else { putenv('SYMFONY_PHPUNIT_VERSION=9.5'); } } -if (!getenv('SYMFONY_PATCH_TYPE_DECLARATIONS')) { +if (!getenv('SYMFONY_PATCH_TYPE_DECLARATIONS') && \PHP_VERSION_ID >= 70300) { putenv('SYMFONY_PATCH_TYPE_DECLARATIONS=deprecations=1'); } if (getcwd() === realpath(__DIR__.'/src/Symfony/Bridge/PhpUnit')) { diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000000000..3f12f1331c272 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php index 8415ee14b63cb..9b3c1595a41f0 100644 --- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php +++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php @@ -164,11 +164,22 @@ private function initializeListeners(string $eventName) private function initializeSubscribers() { $this->initializedSubscribers = true; + + $eventListeners = $this->listeners; + // reset eventListener to respect priority: EventSubscribers have a higher priority + $this->listeners = []; foreach ($this->subscribers as $id => $subscriber) { if (\is_string($subscriber)) { parent::addEventSubscriber($this->subscribers[$id] = $this->container->get($subscriber)); } } + foreach ($eventListeners as $event => $listeners) { + if (!isset($this->listeners[$event])) { + $this->listeners[$event] = []; + } + $this->listeners[$event] += $listeners; + } + $this->subscribers = []; } /** diff --git a/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php b/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php index 2ad16dcd4de24..d3d25c17b275d 100644 --- a/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php +++ b/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php @@ -12,7 +12,6 @@ namespace Symfony\Bridge\Doctrine\Test; use Doctrine\Common\Annotations\AnnotationReader; -use Doctrine\Common\Cache\ArrayCache; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; @@ -62,8 +61,6 @@ public static function createTestConfiguration() $config->setProxyDir(sys_get_temp_dir()); $config->setProxyNamespace('SymfonyTests\Doctrine'); $config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader())); - $config->setQueryCacheImpl(new ArrayCache()); - $config->setMetadataCacheImpl(new ArrayCache()); return $config; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php index a26ecbb35bb24..c77c13e59fecb 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php @@ -146,11 +146,14 @@ public function testAddEventListenerAndSubscriberAfterDispatchEvent() public function testGetListenersForEvent() { + $this->evm = new ContainerAwareEventManager($this->container, ['lazy2']); + $this->container->set('lazy', $listener1 = new MyListener()); + $this->container->set('lazy2', $subscriber1 = new MySubscriber(['foo'])); $this->evm->addEventListener('foo', 'lazy'); $this->evm->addEventListener('foo', $listener2 = new MyListener()); - $this->assertSame([$listener1, $listener2], array_values($this->evm->getListeners('foo'))); + $this->assertSame([$subscriber1, $listener1, $listener2], array_values($this->evm->getListeners('foo'))); } public function testGetListeners() diff --git a/src/Symfony/Bridge/PhpUnit/.gitignore b/src/Symfony/Bridge/PhpUnit/.gitignore index 9d8c4aadaf9f5..c49a5d8df5c65 100644 --- a/src/Symfony/Bridge/PhpUnit/.gitignore +++ b/src/Symfony/Bridge/PhpUnit/.gitignore @@ -1,4 +1,3 @@ vendor/ composer.lock phpunit.xml -Tests/DeprecationErrorHandler/fake_vendor/symfony/error-handler/DebugClassLoader.php diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index ee0fe1e4b844a..feabafb760bde 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -125,43 +125,47 @@ public function handleError($type, $msg, $file, $line, $context = []) return \call_user_func(self::getPhpUnitErrorHandler(), $type, $msg, $file, $line, $context); } - $deprecation = new Deprecation($msg, debug_backtrace(), $file); + $trace = debug_backtrace(); + + if (isset($trace[1]['function'], $trace[1]['args'][0]) && ('trigger_error' === $trace[1]['function'] || 'user_error' === $trace[1]['function'])) { + $msg = $trace[1]['args'][0]; + } + + $deprecation = new Deprecation($msg, $trace, $file); if ($deprecation->isMuted()) { return null; } if ($this->getConfiguration()->isBaselineDeprecation($deprecation)) { return null; } - $group = 'other'; - if ($deprecation->originatesFromAnObject()) { - $class = $deprecation->originatingClass(); - $method = $deprecation->originatingMethod(); - $msg = $deprecation->getMessage(); + $msg = $deprecation->getMessage(); - if (error_reporting() & $type) { - $group = 'unsilenced'; - } elseif ($deprecation->isLegacy()) { - $group = 'legacy'; - } else { - $group = [ - Deprecation::TYPE_SELF => 'self', - Deprecation::TYPE_DIRECT => 'direct', - Deprecation::TYPE_INDIRECT => 'indirect', - Deprecation::TYPE_UNDETERMINED => 'other', - ][$deprecation->getType()]; - } + if (error_reporting() & $type) { + $group = 'unsilenced'; + } elseif ($deprecation->isLegacy()) { + $group = 'legacy'; + } else { + $group = [ + Deprecation::TYPE_SELF => 'self', + Deprecation::TYPE_DIRECT => 'direct', + Deprecation::TYPE_INDIRECT => 'indirect', + Deprecation::TYPE_UNDETERMINED => 'other', + ][$deprecation->getType()]; + } - if ($this->getConfiguration()->shouldDisplayStackTrace($msg)) { - echo "\n".ucfirst($group).' '.$deprecation->toString(); + if ($this->getConfiguration()->shouldDisplayStackTrace($msg)) { + echo "\n".ucfirst($group).' '.$deprecation->toString(); - exit(1); - } - if ('legacy' !== $group) { - $this->deprecationGroups[$group]->addNoticeFromObject($msg, $class, $method); - } else { - $this->deprecationGroups[$group]->addNotice(); - } + exit(1); + } + + if ('legacy' === $group) { + $this->deprecationGroups[$group]->addNotice(); + } else if ($deprecation->originatesFromAnObject()) { + $class = $deprecation->originatingClass(); + $method = $deprecation->originatingMethod(); + $this->deprecationGroups[$group]->addNoticeFromObject($msg, $class, $method); } else { $this->deprecationGroups[$group]->addNoticeFromProceduralCode($msg); } diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php index 3a5c6c1d08d41..3e3ebef48c7c3 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php @@ -60,25 +60,33 @@ public function __construct($message, array $trace, $file) } $this->trace = $trace; - - if ('trigger_error' === (isset($trace[1]['function']) ? $trace[1]['function'] : null) - && (DebugClassLoader::class === ($class = (isset($trace[2]['class']) ? $trace[2]['class'] : null)) || LegacyDebugClassLoader::class === $class) - && 'checkClass' === (isset($trace[2]['function']) ? $trace[2]['function'] : null) - && null !== ($extraFile = (isset($trace[2]['args'][1]) ? $trace[2]['args'][1] : null)) - && '' !== $extraFile - && false !== $extraFile = realpath($extraFile) - ) { - $this->getOriginalFilesStack(); - array_splice($this->originalFilesStack, 2, 1, $extraFile); - } - $this->message = $message; - $i = \count($this->trace); - while (1 < $i && $this->lineShouldBeSkipped($this->trace[--$i])) { + + $i = \count($trace); + while (1 < $i && $this->lineShouldBeSkipped($trace[--$i])) { // No-op } - $line = $this->trace[$i]; + + $line = $trace[$i]; $this->triggeringFile = $file; + + for ($j = 1; $j < $i; ++$j) { + if (!isset($trace[$j]['function'], $trace[1 + $j]['class'], $trace[1 + $j]['args'][0])) { + continue; + } + + if ('trigger_error' === $trace[$j]['function'] && !isset($trace[$j]['class'])) { + if (\in_array($trace[1 + $j]['class'], [DebugClassLoader::class, LegacyDebugClassLoader::class], true)) { + $class = $trace[1 + $j]['args'][0]; + $this->triggeringFile = isset($trace[1 + $j]['args'][1]) ? realpath($trace[1 + $j]['args'][1]) : (new \ReflectionClass($class))->getFileName(); + $this->getOriginalFilesStack(); + array_splice($this->originalFilesStack, 0, $j, [$this->triggeringFile]); + } + + break; + } + } + if (isset($line['object']) || isset($line['class'])) { set_error_handler(function () {}); $parsedMsg = unserialize($this->message); @@ -101,12 +109,19 @@ public function __construct($message, array $trace, $file) return; } - if (isset($line['class']) && 0 === strpos($line['class'], SymfonyTestsListenerFor::class)) { + if (!isset($line['class'], $trace[$i - 2]['function']) || 0 !== strpos($line['class'], SymfonyTestsListenerFor::class)) { + $this->originClass = isset($line['object']) ? \get_class($line['object']) : $line['class']; + $this->originMethod = $line['function']; + return; } - $this->originClass = isset($line['object']) ? \get_class($line['object']) : $line['class']; - $this->originMethod = $line['function']; + if ('trigger_error' !== $trace[$i - 2]['function'] || isset($trace[$i - 2]['class'])) { + $this->originClass = \get_class($line['args'][0]); + $this->originMethod = $line['args'][0]->getName(); + + return; + } } } @@ -140,7 +155,9 @@ public function originatingClass() throw new \LogicException('Check with originatesFromAnObject() before calling this method.'); } - return $this->originClass; + $class = $this->originClass; + + return false !== strpos($class, "@anonymous\0") ? (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous' : $class; } /** @@ -168,8 +185,7 @@ public function getMessage() */ public function isLegacy() { - $class = $this->originatingClass(); - if ((new \ReflectionClass($class))->isInternal()) { + if (!$this->originClass || (new \ReflectionClass($this->originClass))->isInternal()) { return false; } @@ -178,8 +194,8 @@ public function isLegacy() return 0 === strpos($method, 'testLegacy') || 0 === strpos($method, 'provideLegacy') || 0 === strpos($method, 'getLegacy') - || strpos($class, '\Legacy') - || \in_array('legacy', Test::getGroups($class, $method), true); + || strpos($this->originClass, '\Legacy') + || \in_array('legacy', Test::getGroups($this->originClass, $method), true); } /** @@ -205,11 +221,10 @@ public function isMuted() */ public function getType() { - $triggeringFilePathType = $this->getPathType($this->triggeringFile); - if (self::PATH_TYPE_SELF === $triggeringFilePathType) { + if (self::PATH_TYPE_SELF === $pathType = $this->getPathType($this->triggeringFile)) { return self::TYPE_SELF; } - if (self::PATH_TYPE_UNDETERMINED === $triggeringFilePathType) { + if (self::PATH_TYPE_UNDETERMINED === $pathType) { return self::TYPE_UNDETERMINED; } $erroringFile = $erroringPackage = null; @@ -218,10 +233,10 @@ public function getType() if ('-' === $file || 'Standard input code' === $file || !realpath($file)) { continue; } - if (self::PATH_TYPE_SELF === $this->getPathType($file)) { + if (self::PATH_TYPE_SELF === $pathType = $this->getPathType($file)) { return self::TYPE_DIRECT; } - if (self::PATH_TYPE_UNDETERMINED === $this->getPathType($file)) { + if (self::PATH_TYPE_UNDETERMINED === $pathType) { return self::TYPE_UNDETERMINED; } if (null !== $erroringFile && null !== $erroringPackage) { @@ -243,7 +258,7 @@ private function getOriginalFilesStack() if (null === $this->originalFilesStack) { $this->originalFilesStack = []; foreach ($this->trace as $frame) { - if (!isset($frame['file']) || \in_array($frame['function'], ['require', 'require_once', 'include', 'include_once'], true)) { + if (!isset($frame['file'], $frame['function']) || (!isset($frame['class']) && \in_array($frame['function'], ['require', 'require_once', 'include', 'include_once'], true))) { continue; } @@ -269,13 +284,10 @@ private function getPackage($path) $relativePath = substr($path, \strlen($vendorRoot) + 1); $vendor = strstr($relativePath, \DIRECTORY_SEPARATOR, true); if (false === $vendor) { - throw new \RuntimeException(sprintf('Could not find directory separator "%s" in path "%s".', \DIRECTORY_SEPARATOR, $relativePath)); + return 'symfony'; } - return rtrim($vendor.'/'.strstr(substr( - $relativePath, - \strlen($vendor) + 1 - ), \DIRECTORY_SEPARATOR, true), '/'); + return rtrim($vendor.'/'.strstr(substr($relativePath, \strlen($vendor) + 1), \DIRECTORY_SEPARATOR, true), '/'); } } @@ -289,6 +301,13 @@ private static function getVendors() { if (null === self::$vendors) { self::$vendors = $paths = []; + self::$vendors[] = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Legacy'; + if (class_exists(DebugClassLoader::class, false)) { + self::$vendors[] = \dirname((new \ReflectionClass(DebugClassLoader::class))->getFileName()); + } + if (class_exists(LegacyDebugClassLoader::class, false)) { + self::$vendors[] = \dirname((new \ReflectionClass(LegacyDebugClassLoader::class))->getFileName()); + } foreach (get_declared_classes() as $class) { if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { $r = new \ReflectionClass($class); @@ -364,10 +383,9 @@ public function toString() $reflection->setAccessible(true); $reflection->setValue($exception, $this->trace); - return 'deprecation triggered by '.$this->originatingClass().'::'.$this->originatingMethod().':'. - "\n".$this->message. - "\nStack trace:". - "\n".str_replace(' '.getcwd().\DIRECTORY_SEPARATOR, ' ', $exception->getTraceAsString()). - "\n"; + return ($this->originatesFromAnObject() ? 'deprecation triggered by '.$this->originatingClass().'::'.$this->originatingMethod().":\n" : '') + .$this->message."\n" + ."Stack trace:\n" + .str_replace(' '.getcwd().\DIRECTORY_SEPARATOR, ' ', $exception->getTraceAsString())."\n"; } } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php index f36c689099ec8..9cb0a0e32ce3a 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php @@ -174,6 +174,8 @@ public function testGetTypeDetectsSelf(string $expectedType, string $message, st { $trace = [ ['class' => 'MyClass1', 'function' => 'myMethod'], + ['function' => 'trigger_error'], + ['class' => SymfonyTestsListenerTrait::class, 'function' => 'endTest'], ['class' => $traceClass, 'function' => 'myMethod'], ]; $deprecation = new Deprecation($message, $trace, $file); @@ -183,6 +185,11 @@ public function testGetTypeDetectsSelf(string $expectedType, string $message, st public function providerGetTypeUsesRightTrace() { $vendorDir = self::getVendorDir(); + $fakeTrace = [ + ['function' => 'trigger_error'], + ['class' => SymfonyTestsListenerTrait::class, 'function' => 'endTest'], + ['class' => SymfonyTestsListenerForV5::class, 'function' => 'endTest'], + ]; return [ 'no_file_in_stack' => [Deprecation::TYPE_DIRECT, '', [['function' => 'myfunc1'], ['function' => 'myfunc2']]], @@ -205,7 +212,7 @@ public function providerGetTypeUsesRightTrace() $vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile2.php', ], ]), - [['function' => 'myfunc1'], ['class' => SymfonyTestsListenerForV5::class, 'method' => 'mymethod']], + $fakeTrace, ], 'serialized_stack_files_from_various_packages' => [ Deprecation::TYPE_INDIRECT, @@ -218,7 +225,7 @@ public function providerGetTypeUsesRightTrace() $vendorDir.'/myfakevendor/myfakepackage2/MyFakeFile.php', ], ]), - [['function' => 'myfunc1'], ['class' => SymfonyTestsListenerForV5::class, 'method' => 'mymethod']], + $fakeTrace, ], ]; } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/debug_class_loader_autoload.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/debug_class_loader_autoload.phpt index 781027e84fe66..04e64d33e46b6 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/debug_class_loader_autoload.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/debug_class_loader_autoload.phpt @@ -30,16 +30,6 @@ EOPHP ); require __DIR__.'/fake_vendor/autoload.php'; -// We need the real DebugClassLoader FQCN but in a vendor path. -if (!file_exists($errorHandlerRootDir = __DIR__.'/../../../../Component/ErrorHandler')) { - if (!file_exists($errorHandlerRootDir = __DIR__.'/../../vendor/symfony/error-handler')) { - die('Could not find the ErrorHandler component root directory.'); - } -} - -file_put_contents($fakeDebugClassLoadPath = __DIR__.'/fake_vendor/symfony/error-handler/DebugClassLoader.php', file_get_contents($errorHandlerRootDir.'/DebugClassLoader.php')); -require $fakeDebugClassLoadPath; - \Symfony\Component\ErrorHandler\DebugClassLoader::enable(); new \App\Services\BarService(); diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/partially_quiet.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/partially_quiet.phpt index f1fb64ed137ba..83b135b34bab7 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/partially_quiet.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/partially_quiet.phpt @@ -24,7 +24,7 @@ require __DIR__.'/fake_vendor/acme/outdated-lib/outdated_file.php'; --EXPECTF-- Unsilenced deprecation notices (3) -Remaining direct deprecation notices (1) +Remaining direct deprecation notices (2) Remaining indirect deprecation notices (1) @@ -33,5 +33,3 @@ Remaining indirect deprecation notices (1) Legacy deprecation notices (2) -Other deprecation notices (1) - diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_vendor.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_vendor.phpt index 174e2ba89b54e..c9b323f6d5ad1 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_vendor.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_vendor.phpt @@ -29,13 +29,11 @@ Unsilenced deprecation notices (3) 1x: unsilenced bar deprecation 1x in FooTestCase::testNonLegacyBar -Remaining direct deprecation notices (1) +Remaining direct deprecation notices (2) + + 1x: root deprecation 1x: silenced bar deprecation 1x in FooTestCase::testNonLegacyBar Legacy deprecation notices (2) - -Other deprecation notices (1) - - 1x: root deprecation diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index 6b4407cd6059d..077050688b3c9 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -10,7 +10,7 @@ */ // Please update when phpunit needs to be reinstalled with fresh deps: -// Cache-Id: 2020-01-31 10:00 UTC +// Cache-Id: 2021-02-04 11:00 UTC error_reporting(-1); diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 27e6daba7e505..1a1f364eb9a85 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -30,6 +30,7 @@ "symfony/form": "^5.1.9", "symfony/http-foundation": "^4.4|^5.0", "symfony/http-kernel": "^4.4|^5.0", + "symfony/intl": "^4.4|^5.0", "symfony/mime": "^5.2", "symfony/polyfill-intl-icu": "~1.0", "symfony/property-info": "^4.4|^5.1", diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 9274d7e70baf6..392541e656848 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -333,6 +333,11 @@ private function filterCatalogue(MessageCatalogue $catalogue, string $domain): M foreach ($catalogue->getResources() as $resource) { $filteredCatalogue->addResource($resource); } + if ($metadata = $catalogue->getMetadata('', $intlDomain)) { + foreach ($metadata as $k => $v) { + $filteredCatalogue->setMetadata($k, $v, $intlDomain); + } + } if ($metadata = $catalogue->getMetadata('', $domain)) { foreach ($metadata as $k => $v) { $filteredCatalogue->setMetadata($k, $v, $domain); diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 6ab4f84169376..a0efab6b5ba64 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -97,7 +97,7 @@ public function getConfigTreeBuilder() ->enumPrototype() ->values([ 'forwarded', - 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', + 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix', ]) ->end() ->end() @@ -1446,7 +1446,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode) ->info('A network interface name, IP address, a host name or a UNIX socket to bind to.') ->end() ->booleanNode('verify_peer') - ->info('Indicates if the peer should be verified in a SSL/TLS context.') + ->info('Indicates if the peer should be verified in an SSL/TLS context.') ->end() ->booleanNode('verify_host') ->info('Indicates if the host should exist as a certificate common name.') @@ -1589,7 +1589,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode) ->info('A network interface name, IP address, a host name or a UNIX socket to bind to.') ->end() ->booleanNode('verify_peer') - ->info('Indicates if the peer should be verified in a SSL/TLS context.') + ->info('Indicates if the peer should be verified in an SSL/TLS context.') ->end() ->booleanNode('verify_host') ->info('Indicates if the host should exist as a certificate common name.') diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index fdcd199772eec..c6cd60cc32fb1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1220,24 +1220,26 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder // Register translation resources if ($dirs) { $files = []; - $finder = Finder::create() - ->followLinks() - ->files() - ->filter(function (\SplFileInfo $file) { - return 2 <= substr_count($file->getBasename(), '.') && preg_match('/\.\w+$/', $file->getBasename()); - }) - ->in($dirs) - ->sortByName() - ; - foreach ($finder as $file) { - $fileNameParts = explode('.', basename($file)); - $locale = $fileNameParts[\count($fileNameParts) - 2]; - if (!isset($files[$locale])) { - $files[$locale] = []; - } + foreach ($dirs as $dir) { + $finder = Finder::create() + ->followLinks() + ->files() + ->filter(function (\SplFileInfo $file) { + return 2 <= substr_count($file->getBasename(), '.') && preg_match('/\.\w+$/', $file->getBasename()); + }) + ->in($dir) + ->sortByName() + ; + foreach ($finder as $file) { + $fileNameParts = explode('.', basename($file)); + $locale = $fileNameParts[\count($fileNameParts) - 2]; + if (!isset($files[$locale])) { + $files[$locale] = []; + } - $files[$locale][] = (string) $file; + $files[$locale][] = (string) $file; + } } $projectDir = $container->getParameter('kernel.project_dir'); @@ -1441,8 +1443,8 @@ private function registerAnnotationsConfiguration(array $config, ContainerBuilde } $container - ->getDefinition('annotations.filesystem_cache') - ->replaceArgument(0, $cacheDir) + ->getDefinition('annotations.filesystem_cache_adapter') + ->replaceArgument(2, $cacheDir) ; $cacheService = 'annotations.filesystem_cache'; @@ -2303,6 +2305,7 @@ private function resolveTrustedHeaders(array $headers): int case 'x-forwarded-host': $trustedHeaders |= Request::HEADER_X_FORWARDED_HOST; break; case 'x-forwarded-proto': $trustedHeaders |= Request::HEADER_X_FORWARDED_PROTO; break; case 'x-forwarded-port': $trustedHeaders |= Request::HEADER_X_FORWARDED_PORT; break; + case 'x-forwarded-prefix': $trustedHeaders |= Request::HEADER_X_FORWARDED_PREFIX; break; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php index cc66f6f6056bb..187d9da6642d0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php @@ -15,9 +15,9 @@ use Doctrine\Common\Annotations\AnnotationRegistry; use Doctrine\Common\Annotations\CachedReader; use Doctrine\Common\Annotations\Reader; -use Doctrine\Common\Cache\ArrayCache; -use Doctrine\Common\Cache\FilesystemCache; use Symfony\Bundle\FrameworkBundle\CacheWarmer\AnnotationsCacheWarmer; +use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\PhpArrayAdapter; use Symfony\Component\Cache\DoctrineProvider; @@ -35,15 +35,24 @@ ->set('annotations.cached_reader', CachedReader::class) ->args([ service('annotations.reader'), - inline_service(ArrayCache::class), + inline_service(DoctrineProvider::class)->args([ + inline_service(ArrayAdapter::class) + ]), abstract_arg('Debug-Flag'), ]) - ->set('annotations.filesystem_cache', FilesystemCache::class) + ->set('annotations.filesystem_cache_adapter', FilesystemAdapter::class) ->args([ + '', + 0, abstract_arg('Cache-Directory'), ]) + ->set('annotations.filesystem_cache', DoctrineProvider::class) + ->args([ + service('annotations.filesystem_cache_adapter'), + ]) + ->set('annotations.cache_warmer', AnnotationsCacheWarmer::class) ->args([ service('annotations.reader'), @@ -61,6 +70,7 @@ service('cache.annotations'), ]), ]) + ->tag('container.hot_path') ->alias('annotation_reader', 'annotations.reader') ->alias(Reader::class, 'annotation_reader'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.php index 51c6ae38f2dd1..e4c0745c6094e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.php @@ -97,7 +97,10 @@ ->tag('form.type') ->set('form.type.choice', ChoiceType::class) - ->args([service('form.choice_list_factory')]) + ->args([ + service('form.choice_list_factory'), + service('translator')->ignoreOnInvalid(), + ]) ->tag('form.type') ->set('form.type.file', FileType::class) diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php b/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php index 36533e12f08a8..5bdf54565d647 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php @@ -61,7 +61,7 @@ public function load($resource, string $type = null) // - this handles the case and prevents the second fatal error // by triggering an exception beforehand. - throw new LoaderLoadException($resource, null, null, null, $type); + throw new LoaderLoadException($resource, null, 0, null, $type); } $this->loading = true; diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php index 038d8722b7ed5..b70437374ad24 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php @@ -180,14 +180,16 @@ private function resolve($value) $resolved = ($this->paramFetcher)($match[1]); - if (\is_bool($resolved)) { - $resolved = (string) (int) $resolved; - } - - if (\is_string($resolved) || is_numeric($resolved)) { + if (is_scalar($resolved)) { $this->collectedParameters[$match[1]] = $resolved; - return (string) $this->resolve($resolved); + if (\is_string($resolved)) { + $resolved = $this->resolve($resolved); + } + + if (is_scalar($resolved)) { + return false === $resolved ? '0' : (string) $resolved; + } } throw new RuntimeException(sprintf('The container parameter "%s", used in the route configuration value "%s", must be a string or numeric, but it is of type "%s".', $match[1], $value, get_debug_type($resolved))); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php index 5f74f1f889a92..2c25b8e9f27ca 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; @@ -38,13 +39,14 @@ protected function setUp(): void protected function tearDown(): void { - $this->fs->remove($this->kernel->getProjectDir()); + try { + $this->fs->remove($this->kernel->getProjectDir()); + } catch (IOException $e) { + } } public function testCacheIsFreshAfterCacheClearedWithWarmup() { - $this->fs->mkdir($this->kernel->getProjectDir()); - $input = new ArrayInput(['cache:clear']); $application = new Application($this->kernel); $application->setCatchExceptions(false); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 95171449f9b7a..960eda35d0b62 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -836,6 +836,19 @@ public function testTranslator() $files, '->registerTranslatorConfiguration() finds translation resources with dots in domain' ); + $this->assertContains(strtr(__DIR__.'/translations/security.en.yaml', '/', \DIRECTORY_SEPARATOR), $files); + + $positionOverridingTranslationFile = array_search(strtr(realpath(__DIR__.'/translations/security.en.yaml'), '/', \DIRECTORY_SEPARATOR), $files); + + if (false !== $positionCoreTranslationFile = array_search(strtr(realpath(__DIR__.'/../../../../Component/Security/Core/Resources/translations/security.en.xlf'), '/', \DIRECTORY_SEPARATOR), $files)) { + $this->assertContains(strtr(realpath(__DIR__.'/../../../../Component/Security/Core/Resources/translations/security.en.xlf'), '/', \DIRECTORY_SEPARATOR), $files); + } else { + $this->assertContains(strtr(realpath(__DIR__.'/../../vendor/symfony/security-core/Resources/translations/security.en.xlf'), '/', \DIRECTORY_SEPARATOR), $files); + + $positionCoreTranslationFile = array_search(strtr(realpath(__DIR__.'/../../vendor/symfony/security-core/Resources/translations/security.en.xlf'), '/', \DIRECTORY_SEPARATOR), $files); + } + + $this->assertGreaterThan($positionCoreTranslationFile, $positionOverridingTranslationFile); $calls = $container->getDefinition('translator.default')->getMethodCalls(); $this->assertEquals(['fr'], $calls[1][1][0]); @@ -915,7 +928,7 @@ public function testAnnotations() $container->addCompilerPass(new TestAnnotationsPass()); $container->compile(); - $this->assertEquals($container->getParameter('kernel.cache_dir').'/annotations', $container->getDefinition('annotations.filesystem_cache')->getArgument(0)); + $this->assertEquals($container->getParameter('kernel.cache_dir').'/annotations', $container->getDefinition('annotations.filesystem_cache_adapter')->getArgument(2)); $this->assertSame('annotations.filesystem_cache', (string) $container->getDefinition('annotation_reader')->getArgument(1)); } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/symfony/error-handler/.gitkeep b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/translations/security.en.yaml similarity index 100% rename from src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/symfony/error-handler/.gitkeep rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/translations/security.en.yaml diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/Fixtures/with_condition.yaml b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/Fixtures/with_condition.yaml new file mode 100644 index 0000000000000..c97edc1a42542 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/Fixtures/with_condition.yaml @@ -0,0 +1,3 @@ +foo: + path: /foo + condition: '%parameter.condition%' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php index 91d9c4cfd6d3a..416695ea765ea 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php @@ -14,11 +14,16 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Symfony\Bundle\FrameworkBundle\Routing\Router; +use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\Config\ResourceCheckerConfigCache; +use Symfony\Component\Config\ResourceCheckerConfigCacheFactory; use Symfony\Component\DependencyInjection\Config\ContainerParametersResource; +use Symfony\Component\DependencyInjection\Config\ContainerParametersResourceChecker; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; @@ -503,6 +508,51 @@ public function getNonStringValues() return [[null], [false], [true], [new \stdClass()], [['foo', 'bar']], [[[]]]]; } + /** + * @dataProvider getContainerParameterForRoute + */ + public function testCacheValidityWithContainerParameters($parameter) + { + $cacheDir = sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('router_', true); + + try { + $container = new Container(); + $container->set('routing.loader', new YamlFileLoader(new FileLocator(__DIR__.'/Fixtures'))); + + $container->setParameter('parameter.condition', $parameter); + + $router = new Router($container, 'with_condition.yaml', [ + 'debug' => true, + 'cache_dir' => $cacheDir, + ]); + + $resourceCheckers = [ + new ContainerParametersResourceChecker($container), + ]; + + $router->setConfigCacheFactory(new ResourceCheckerConfigCacheFactory($resourceCheckers)); + + $router->getMatcher(); // trigger cache build + + $cache = new ResourceCheckerConfigCache($cacheDir.\DIRECTORY_SEPARATOR.'url_matching_routes.php', $resourceCheckers); + + $this->assertTrue($cache->isFresh()); + } finally { + if (is_dir($cacheDir)) { + array_map('unlink', glob($cacheDir.\DIRECTORY_SEPARATOR.'*')); + rmdir($cacheDir); + } + } + } + + public function getContainerParameterForRoute() + { + yield 'String' => ['"foo"']; + yield 'Integer' => [0]; + yield 'Boolean true' => [true]; + yield 'Boolean false' => [false]; + } + private function getServiceContainer(RouteCollection $routes): Container { $loader = $this->createMock(LoaderInterface::class); diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 7931966131fb2..09c00ea6a16d6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -52,6 +52,7 @@ "symfony/mime": "^4.4|^5.0", "symfony/process": "^4.4|^5.0", "symfony/security-bundle": "^5.1", + "symfony/security-core": "^4.4|^5.2", "symfony/security-csrf": "^4.4|^5.0", "symfony/security-http": "^4.4|^5.0", "symfony/serializer": "^5.2", diff --git a/src/Symfony/Bundle/SecurityBundle/CacheWarmer/ExpressionCacheWarmer.php b/src/Symfony/Bundle/SecurityBundle/CacheWarmer/ExpressionCacheWarmer.php index 7e72f08b6040f..1ca1f32ecd98e 100644 --- a/src/Symfony/Bundle/SecurityBundle/CacheWarmer/ExpressionCacheWarmer.php +++ b/src/Symfony/Bundle/SecurityBundle/CacheWarmer/ExpressionCacheWarmer.php @@ -40,7 +40,7 @@ public function isOptional() public function warmUp(string $cacheDir) { foreach ($this->expressions as $expression) { - $this->expressionLanguage->parse($expression, ['token', 'user', 'object', 'subject', 'roles', 'request', 'trust_resolver']); + $this->expressionLanguage->parse($expression, ['token', 'user', 'object', 'subject', 'role_names', 'request', 'trust_resolver']); } return []; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/CacheWarmer/ExpressionCacheWarmerTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/CacheWarmer/ExpressionCacheWarmerTest.php index d1299bffed611..53b16fcdf7774 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/CacheWarmer/ExpressionCacheWarmerTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/CacheWarmer/ExpressionCacheWarmerTest.php @@ -26,8 +26,8 @@ public function testWarmUp() $expressionLang->expects($this->exactly(2)) ->method('parse') ->withConsecutive( - [$expressions[0], ['token', 'user', 'object', 'subject', 'roles', 'request', 'trust_resolver']], - [$expressions[1], ['token', 'user', 'object', 'subject', 'roles', 'request', 'trust_resolver']] + [$expressions[0], ['token', 'user', 'object', 'subject', 'role_names', 'request', 'trust_resolver']], + [$expressions[1], ['token', 'user', 'object', 'subject', 'role_names', 'request', 'trust_resolver']] ); (new ExpressionCacheWarmer($expressions, $expressionLang))->warmUp(''); diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php index 977dd28a8807c..43e0602acacb5 100644 --- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php +++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php @@ -311,7 +311,7 @@ public function submit(Form $form, array $values = [], array $serverParameters = * @param string $button The text content, id, value or name of the form