Skip to content

Commit fa0f68b

Browse files
authored
Merge pull request #2400 from mbabker/sf-7
Add support for Symfony 7 where able
2 parents 3fafc1e + fadaba5 commit fa0f68b

File tree

55 files changed

+728
-477
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+728
-477
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,54 @@ jobs:
1818
continue-on-error: ${{ matrix.can-fail }}
1919

2020
strategy:
21+
fail-fast: false
2122
matrix:
2223
include:
23-
- php-version: 7.2
24-
composer-flags: "--prefer-lowest "
24+
- php-version: "7.4"
25+
composer-flags: "--prefer-lowest"
26+
symfony-require: "5.4.*"
2527
can-fail: false
26-
- php-version: 7.3
28+
- php-version: "7.4"
2729
composer-flags: ""
2830
can-fail: false
29-
- php-version: 7.4
31+
- php-version: "7.4"
3032
composer-flags: ""
3133
symfony-require: "5.4.*"
3234
can-fail: false
3335
coverage: yes
34-
- php-version: 8.0
36+
- php-version: "8.0"
37+
composer-flags: ""
38+
can-fail: false
39+
symfony-require: "5.4.*"
40+
- php-version: "8.1"
41+
composer-flags: ""
42+
can-fail: false
43+
symfony-require: "6.4.*"
44+
- php-version: "8.2"
3545
composer-flags: ""
3646
can-fail: false
37-
symfony-require: "6.0.*"
38-
- php-version: 8.1
47+
symfony-require: "6.4.*"
48+
- php-version: "8.3"
3949
composer-flags: ""
4050
can-fail: false
41-
symfony-require: "6.1.*"
42-
- php-version: 8.2
51+
symfony-require: "6.4.*"
52+
- php-version: "8.3"
4353
composer-flags: ""
4454
can-fail: false
45-
symfony-require: "6.2.*"
46-
- php-version: 8.2
55+
symfony-require: "6.4.*"
56+
remove-sensio-bundle: yes # Smoke test with SensioFrameworkExtraBundle removed on latest Symfony LTS
57+
- php-version: "8.2"
4758
composer-flags: ""
4859
can-fail: false
49-
symfony-require: "6.3.*"
50-
- php-version: 8.2
60+
symfony-require: "7.0.*"
61+
remove-sensio-bundle: yes # SensioFrameworkExtraBundle is not compatible with Symfony 7.0 or later
62+
- php-version: "8.3"
5163
composer-flags: ""
5264
can-fail: true # we don't want to fail the build if we are incompatible with the next (unstable) Symfony version
65+
remove-sensio-bundle: yes # SensioFrameworkExtraBundle is not compatible with Symfony 7.0 or later
66+
67+
env:
68+
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5369

5470
steps:
5571
- name: "Checkout"
@@ -78,11 +94,17 @@ jobs:
7894
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
7995
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
8096

97+
- name: "Remove SensioFrameworkExtraBundle if required"
98+
if: "${{ matrix.remove-sensio-bundle == 'yes' }}"
99+
env:
100+
SYMFONY_REQUIRE: "${{ matrix.symfony-require }}"
101+
run: |
102+
composer remove --no-update --dev sensio/framework-extra-bundle
103+
81104
- name: "Install dependencies with composer"
82105
env:
83106
SYMFONY_REQUIRE: "${{ matrix.symfony-require }}"
84107
run: |
85-
composer remove friendsofphp/php-cs-fixer --dev --no-update
86108
composer update --no-interaction --no-progress ${{ matrix.composer-flags }}
87109
88110
- name: "Run PHPUnit"

Controller/Annotations/FileParam.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
*
2323
* @Annotation
2424
* @NamedArgumentConstructor
25-
* @Target("METHOD")
25+
* @Target({"CLASS", "METHOD"})
2626
*
2727
* @author Ener-Getick <[email protected]>
2828
*/
29-
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
29+
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
3030
class FileParam extends AbstractParam
3131
{
3232
/** @var bool */

Controller/Annotations/RequestParam.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
*
1919
* @Annotation
2020
* @NamedArgumentConstructor
21-
* @Target("METHOD")
21+
* @Target({"CLASS", "METHOD"})
2222
*
2323
* @author Jordi Boggiano <[email protected]>
2424
* @author Boris Guéry <[email protected]>
2525
*/
26-
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
26+
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
2727
class RequestParam extends AbstractScalarParam
2828
{
2929
/** @var bool */

Controller/Annotations/Route.php

Lines changed: 77 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,28 @@
1111

1212
namespace FOS\RestBundle\Controller\Annotations;
1313

14-
use Symfony\Component\Routing\Annotation\Route as BaseRoute;
14+
use Symfony\Component\Routing\Annotation\Route as BaseAnnotationRoute;
15+
use Symfony\Component\Routing\Attribute\Route as BaseAttributeRoute;
16+
17+
if (class_exists(BaseAttributeRoute::class)) {
18+
/**
19+
* Compatibility layer for Symfony 6.4 and later.
20+
*
21+
* @internal
22+
*/
23+
class CompatRoute extends BaseAttributeRoute
24+
{
25+
}
26+
} else {
27+
/**
28+
* Compatibility layer for Symfony 6.3 and earlier.
29+
*
30+
* @internal
31+
*/
32+
class CompatRoute extends BaseAnnotationRoute
33+
{
34+
}
35+
}
1536

1637
/**
1738
* Route annotation class.
@@ -21,8 +42,17 @@
2142
* @Target({"CLASS", "METHOD"})
2243
*/
2344
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
24-
class Route extends BaseRoute
45+
class Route extends CompatRoute
2546
{
47+
/**
48+
* @param array|string $data
49+
* @param array|string|null $path
50+
* @param string[] $requirements
51+
* @param string[]|string $methods
52+
* @param string[]|string $schemes
53+
*
54+
* @throws \TypeError if the $data argument is an unsupported type
55+
*/
2656
public function __construct(
2757
$data = [],
2858
$path = null,
@@ -41,78 +71,56 @@ public function __construct(
4171
bool $stateless = null,
4272
string $env = null
4373
) {
44-
// BC layer for symfony < 5.2
45-
// Before symfony/routing 5.2 the constructor only had one parameter
46-
$method = new \ReflectionMethod(BaseRoute::class, '__construct');
47-
if (1 === $method->getNumberOfParameters()) {
74+
// Use Reflection to get the constructor from the parent class two levels up (accounting for our compat definition)
75+
$method = (new \ReflectionClass($this))->getParentClass()->getParentClass()->getMethod('__construct');
76+
77+
// The $data constructor parameter was removed in Symfony 6.0 in favor of named arguments
78+
if ('data' === $method->getParameters()[0]->getName()) {
79+
parent::__construct(
80+
$data,
81+
$path,
82+
$name,
83+
$requirements,
84+
$options,
85+
$defaults,
86+
$host,
87+
$methods,
88+
$schemes,
89+
$condition,
90+
$priority,
91+
$locale,
92+
$format,
93+
$utf8,
94+
$stateless,
95+
$env
96+
);
97+
} else {
4898
if (\is_string($data)) {
49-
$path = $data;
50-
$data = [];
99+
$data = ['path' => $data];
51100
} elseif (!\is_array($data)) {
52101
throw new \TypeError(sprintf('"%s": Argument $data is expected to be a string or array, got "%s".', __METHOD__, get_debug_type($data)));
102+
} elseif (0 !== count($data) && [] === \array_intersect(\array_keys($data), ['path', 'name', 'requirements', 'options', 'defaults', 'host', 'methods', 'schemes', 'condition', 'priority', 'locale', 'format', 'utf8', 'stateless', 'env'])) {
103+
$localizedPaths = $data;
104+
$data = ['path' => $localizedPaths];
53105
}
54106

55-
$data['path'] = $path;
56-
$data['name'] = $name;
57-
$data['requirements'] = $requirements;
58-
$data['options'] = $options;
59-
$data['defaults'] = $defaults;
60-
$data['host'] = $host;
61-
$data['methods'] = $methods;
62-
$data['schemes'] = $schemes;
63-
$data['condition'] = $condition;
64-
65-
parent::__construct($data);
66-
} else {
67-
// BC layer for symfony < 6.0
68-
// The constructor parameter $data has been removed since symfony 6.0
69-
if ('data' === $method->getParameters()[0]->getName()) {
70-
parent::__construct(
71-
$data,
72-
$path,
73-
$name,
74-
$requirements,
75-
$options,
76-
$defaults,
77-
$host,
78-
$methods,
79-
$schemes,
80-
$condition,
81-
$priority,
82-
$locale,
83-
$format,
84-
$utf8,
85-
$stateless,
86-
$env
87-
);
88-
} else {
89-
if (\is_string($data)) {
90-
$data = ['path' => $data];
91-
} elseif (!\is_array($data)) {
92-
throw new \TypeError(sprintf('"%s": Argument $data is expected to be a string or array, got "%s".', __METHOD__, get_debug_type($data)));
93-
} elseif (0 !== count($data) && [] === \array_intersect(\array_keys($data), ['path', 'name', 'requirements', 'options', 'defaults', 'host', 'methods', 'schemes', 'condition', 'priority', 'locale', 'format', 'utf8', 'stateless', 'env'])) {
94-
$localizedPaths = $data;
95-
$data = ['path' => $localizedPaths];
96-
}
97-
98-
parent::__construct(
99-
$data['path'] ?? $path,
100-
$data['name'] ?? $name,
101-
$data['requirements'] ?? $requirements,
102-
$data['options'] ?? $options,
103-
$data['defaults'] ?? $defaults,
104-
$data['host'] ?? $host,
105-
$data['methods'] ?? $methods,
106-
$data['schemes'] ?? $schemes,
107-
$data['condition'] ?? $condition,
108-
$data['priority'] ?? $priority,
109-
$data['locale'] ?? $locale,
110-
$data['format'] ?? $format,
111-
$data['utf8'] ?? $utf8,
112-
$data['stateless'] ?? $stateless,
113-
$data['env'] ?? $env
114-
);
115-
}
107+
parent::__construct(
108+
$data['path'] ?? $path,
109+
$data['name'] ?? $name,
110+
$data['requirements'] ?? $requirements,
111+
$data['options'] ?? $options,
112+
$data['defaults'] ?? $defaults,
113+
$data['host'] ?? $host,
114+
$data['methods'] ?? $methods,
115+
$data['schemes'] ?? $schemes,
116+
$data['condition'] ?? $condition,
117+
$data['priority'] ?? $priority,
118+
$data['locale'] ?? $locale,
119+
$data['format'] ?? $format,
120+
$data['utf8'] ?? $utf8,
121+
$data['stateless'] ?? $stateless,
122+
$data['env'] ?? $env
123+
);
116124
}
117125

118126
if (!$this->getMethods()) {

0 commit comments

Comments
 (0)