/
scoper.inc.php
194 lines (187 loc) · 7.42 KB
/
scoper.inc.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<?php
declare(strict_types=1);
use Isolated\Symfony\Component\Finder\Finder;
/**
* Must only scope the packages in vendor/, because:
*
* - config/ references only local configuration
* - src/ references only local classes (with one exception), which need not be scoped
* - vendor/ references external classes (excluding local -wp packages), which need be scoped
*
* In addition, we must exclude all the local WordPress packages,
* because scoping WordPress functions does NOT work.
* @see https://github.com/humbug/php-scoper/issues/303
*
* Excluding the WordPress packages is feasible, because they do
* not reference any external library.
*
* The only exception is getpop/routing-wp, which uses Brain\Cortex:
*
* in getpop/routing-wp/src/Component.php:
* use Brain\Cortex;
*
* in getpop/routing-wp/src/Hooks/SetupCortexHookSet.php:
* use Brain\Cortex\Route\RouteCollectionInterface;
* use Brain\Cortex\Route\RouteInterface;
* use Brain\Cortex\Route\QueryRoute;
*
* Then, manually add these 2 files to scope Brain\Cortex.
* This works without side effects, because there are no WordPress stubs in them.
*/
function convertRelativeToFullPath(string $relativePath): string {
return __DIR__ . '/vendor/' . $relativePath;
}
return [
'prefix' => 'PrefixedByPoP',
'finders' => [
// Scope packages under vendor/, excluding local WordPress packages
Finder::create()
->files()
->ignoreVCS(true)
->notName('/.*\\.md|.*\\.dist|composer\\.lock/')
->exclude([
'tests',
])
->notPath([
// Exclude libraries ending in "-wp"
'#getpop/[a-zA-Z0-9_-]*-wp/#',
'#pop-schema/[a-zA-Z0-9_-]*-wp/#',
'#graphql-by-pop/[a-zA-Z0-9_-]*-wp/#',
// Exclude all composer.json from own libraries (they get broken!)
'#[getpop|pop\-schema|graphql\-by\-pop|graphql\-api]/*/composer.json#',
// Exclude libraries
'#symfony/deprecation-contracts/#',
'#ralouphie/getallheaders/#',
// Exclude tests from libraries
'#nikic/fast-route/test/#',
'#psr/log/Psr/Log/Test/#',
'#symfony/service-contracts/Test/#',
])
->in('vendor'),
Finder::create()->append([
'vendor/getpop/routing-wp/src/Component.php',
'vendor/getpop/routing-wp/src/Hooks/SetupCortexHookSet.php',
])
],
'whitelist' => [
// Own namespaces
// Watch out! Do NOT alter the order of PoPSchema and PoP!
// If PoP comes first, then PoPSchema is still scoped!
'PoPSchema\*',
'PoP\*',
'GraphQLByPoP\*',
'GraphQLAPI\*',
// Own container cache
'PoPContainer\*',
],
'files-whitelist' => [
// Class Composer\InstalledVersions will be regenerated without scope when
// doing `composer dumpautoload`, so skip it
'vendor/composer/InstalledVersions.php',
],
'patchers' => [
function (string $filePath, string $prefix, string $content): string {
/**
* File vendor/nikic/fast-route/src/bootstrap.php has this code:
*
* if (\strpos($class, 'FastRoute\\') === 0) {
* $name = \substr($class, \strlen('FastRoute'));
*
* Fix it
*/
if ($filePath === __DIR__ . DIRECTORY_SEPARATOR . 'vendor/nikic/fast-route/src/bootstrap.php') {
return str_replace(
["'FastRoute\\\\'", "'FastRoute'"],
["'${prefix}\\\\FastRoute\\\\'", "'${prefix}\\\\FastRoute'"],
$content
);
}
/**
* Brain/Cortex is prefixing classes \WP and \WP_Rewrite
* Avoid it!
*/
if (str_starts_with($filePath, __DIR__ . DIRECTORY_SEPARATOR . 'vendor/brain/cortex/')) {
return str_replace(
"\\${prefix}\\WP",
"\\WP",
$content
);
}
/**
* Symfony Polyfill packages.
* The bootstrap*.php files must register functions under the global namespace,
* and the other ones must register constants on the global namespace,
* so remove the namespaced after it's added.
* These files can't be whitelisted, because they may reference a prefixed class
*/
// Pattern to identify Symfony Polyfill bootstrap files
// - vendor/symfony/polyfill-mbstring/bootstrap80.php
// - vendor/symfony/polyfill-php72/bootstrap.php
// - etc
$pattern = '#' . __DIR__ . '/vendor/symfony/polyfill-[a-zA-Z0-9_-]*/bootstrap.*\.php#';
$symfonyPolyfillFilesWithGlobalClass = array_map(
'convertRelativeToFullPath',
[
'symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'symfony/polyfill-php73/Resources/stubs/JsonException.php',
'symfony/polyfill-php80/Resources/stubs/Attribute.php',
'symfony/polyfill-php80/Resources/stubs/Stringable.php',
'symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'symfony/polyfill-php80/Resources/stubs/ValueError.php',
]
);
$isSymfonyPolyfillFileWithGlobalClass = in_array($filePath, $symfonyPolyfillFilesWithGlobalClass);
if (
$isSymfonyPolyfillFileWithGlobalClass
|| preg_match($pattern, $filePath)
) {
// Remove the namespace
$content = str_replace(
"namespace ${prefix};",
'',
$content
);
// Comment out the class_alias too
if ($isSymfonyPolyfillFileWithGlobalClass) {
$content = str_replace(
"\class_alias('${prefix}\\\\",
"//\class_alias('${prefix}\\\\",
$content
);
}
return $content;
}
/**
* In these files, it prefixes the return type `parent`.
* Undo it!
*/
$symfonyPolyfillFilesWithParentReturnType = array_map(
'convertRelativeToFullPath',
[
'symfony/string/AbstractUnicodeString.php',
'symfony/string/ByteString.php',
'symfony/string/UnicodeString.php',
]
);
if (in_array($filePath, $symfonyPolyfillFilesWithParentReturnType)) {
return str_replace(
"\\${prefix}\\parent",
'parent',
$content
);
}
/**
* It changes the path to Parsedown source files in its composer.json
* Undo it!
*/
if ($filePath == convertRelativeToFullPath('erusev/parsedown/composer.json')) {
return str_replace(
['"\\/Parsedown\\/"', '"psr-4"'],
['""', '"psr-0"'],
$content
);
}
return $content;
},
],
];