Skip to content

Commit b09e8b3

Browse files
authored
Merge branch 'develop' into bug-entity
2 parents 3045308 + 5a24c0c commit b09e8b3

6 files changed

Lines changed: 162 additions & 14 deletions

File tree

system/Autoloader/FileLocator.php

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -330,19 +330,7 @@ public function listFiles(string $path): array
330330
helper('filesystem');
331331

332332
foreach ($this->getNamespaces() as $namespace) {
333-
$fullPath = $namespace['path'] . $path;
334-
$resolvedPath = realpath($fullPath);
335-
$fullPath = $resolvedPath !== false ? $resolvedPath : $fullPath;
336-
337-
if (! is_dir($fullPath)) {
338-
continue;
339-
}
340-
341-
$tempFiles = get_filenames($fullPath, true, false, false);
342-
343-
if ($tempFiles !== []) {
344-
$files = array_merge($files, $tempFiles);
345-
}
333+
$files = array_merge($files, get_filenames($namespace['path'] . $path, true, false, false));
346334
}
347335

348336
return $files;

system/CodeIgniter.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,29 @@ public function resetForWorkerMode(): void
208208
// Reset timing
209209
$this->startTime = null;
210210
$this->totalTime = 0;
211+
212+
$this->resetKintForWorkerMode();
213+
}
214+
215+
/**
216+
* Resets Kint request-specific state for worker mode.
217+
*/
218+
private function resetKintForWorkerMode(): void
219+
{
220+
if (! CI_DEBUG || ! class_exists(Kint::class, false)) {
221+
return;
222+
}
223+
224+
$csp = service('csp');
225+
if ($csp->enabled()) {
226+
RichRenderer::$js_nonce = $csp->getScriptNonce();
227+
RichRenderer::$css_nonce = $csp->getStyleNonce();
228+
} else {
229+
RichRenderer::$js_nonce = null;
230+
RichRenderer::$css_nonce = null;
231+
}
232+
233+
RichRenderer::$needs_pre_render = true;
211234
}
212235

213236
/**

tests/system/CodeIgniterTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use Config\Filters as FiltersConfig;
3131
use Config\Modules;
3232
use Config\Routing;
33+
use Kint\Renderer\RichRenderer;
3334
use PHPUnit\Framework\Attributes\BackupGlobals;
3435
use PHPUnit\Framework\Attributes\DataProvider;
3536
use PHPUnit\Framework\Attributes\Group;
@@ -1273,6 +1274,15 @@ public function testRouteAttributesDisabledInConfig(): void
12731274

12741275
public function testResetForWorkerMode(): void
12751276
{
1277+
$this->resetServices();
1278+
1279+
$appConfig = config(App::class);
1280+
$appConfig->CSPEnabled = true;
1281+
1282+
RichRenderer::$js_nonce = 'stale-script-nonce';
1283+
RichRenderer::$css_nonce = 'stale-style-nonce';
1284+
RichRenderer::$needs_pre_render = false;
1285+
12761286
$config = new App();
12771287
$codeigniter = new MockCodeIgniter($config);
12781288

@@ -1292,5 +1302,11 @@ public function testResetForWorkerMode(): void
12921302
$this->assertNull($this->getPrivateProperty($codeigniter, 'controller'));
12931303
$this->assertNull($this->getPrivateProperty($codeigniter, 'method'));
12941304
$this->assertNull($this->getPrivateProperty($codeigniter, 'output'));
1305+
1306+
$csp = service('csp');
1307+
1308+
$this->assertSame($csp->getScriptNonce(), RichRenderer::$js_nonce);
1309+
$this->assertSame($csp->getStyleNonce(), RichRenderer::$css_nonce);
1310+
$this->assertTrue(RichRenderer::$needs_pre_render);
12951311
}
12961312
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Version switcher for the user guide sidebar.
3+
*
4+
* Injects the sphinx_rtd_theme's native ".switch-menus > .version-switch"
5+
* scaffolding above the search box in the left sidebar, containing a <select>
6+
* so readers can jump between:
7+
* - stable: https://codeigniter.com/user_guide/
8+
* - latest (in-progress): https://codeigniter4.github.io/userguide/
9+
* - local build: file:// or localhost, etc. (only shown when not on a deployed host)
10+
*/
11+
(() => {
12+
const VERSIONS = [
13+
{
14+
slug: 'stable',
15+
label: 'Stable',
16+
host: 'codeigniter.com',
17+
pathPrefix: '/user_guide/',
18+
},
19+
{
20+
slug: 'latest (in-progress)',
21+
label: 'Latest (in-progress)',
22+
host: 'codeigniter4.github.io',
23+
pathPrefix: '/userguide/',
24+
},
25+
];
26+
27+
const LOCAL = Object.freeze({
28+
slug: 'local build',
29+
label: 'Local build',
30+
host: null,
31+
pathPrefix: null,
32+
});
33+
34+
const detect_current = () =>
35+
VERSIONS.find((version) => version.host === window.location.hostname) ?? LOCAL;
36+
37+
/*
38+
* Derive the absolute URL of the documentation root by inspecting the
39+
* <script> tag Sphinx always injects for documentation_options.js. Its
40+
* resolved .src is absolute, so we can back out the directory that
41+
* contains _static/, which is the doc root. This works identically for
42+
* http(s), file://, and localhost.
43+
*/
44+
const doc_root_url = () => {
45+
const opts = document.querySelector('script[src*="documentation_options.js"]');
46+
47+
if (!opts) {
48+
return null;
49+
}
50+
51+
const idx = opts.src.lastIndexOf('/_static/');
52+
53+
return idx < 0 ? null : opts.src.slice(0, idx + 1);
54+
};
55+
56+
const current_page_path = () => {
57+
const root = doc_root_url();
58+
59+
if (!root) {
60+
return '';
61+
}
62+
63+
const here = window.location.href.split('#')[0].split('?')[0];
64+
65+
return here.startsWith(root) ? here.slice(root.length) : '';
66+
};
67+
68+
const url_for = ({ host, pathPrefix }) =>
69+
`https://${host}${pathPrefix}${current_page_path()}${window.location.hash}`;
70+
71+
const build = () => {
72+
const searchArea = document.querySelector('.wy-side-nav-search');
73+
const searchForm = searchArea?.querySelector('[role="search"]');
74+
75+
if (!searchArea || !searchForm) {
76+
return;
77+
}
78+
79+
if (searchArea.querySelector('.switch-menus')) {
80+
return;
81+
}
82+
83+
const current = detect_current();
84+
const entries = current === LOCAL ? [LOCAL, ...VERSIONS] : VERSIONS;
85+
86+
const select = document.createElement('select');
87+
select.setAttribute('aria-label', 'Select documentation version');
88+
89+
for (const entry of entries) {
90+
const option = document.createElement('option');
91+
option.value = entry.host ? url_for(entry) : '';
92+
option.textContent = entry.label;
93+
option.selected = entry.slug === current.slug;
94+
select.append(option);
95+
}
96+
97+
select.addEventListener('change', () => {
98+
if (select.value) {
99+
window.location.href = select.value;
100+
}
101+
});
102+
103+
const versionSwitch = document.createElement('div');
104+
versionSwitch.className = 'version-switch';
105+
versionSwitch.append(select);
106+
107+
const switchMenus = document.createElement('div');
108+
switchMenus.className = 'switch-menus';
109+
switchMenus.append(versionSwitch);
110+
111+
searchArea.insertBefore(switchMenus, searchForm);
112+
};
113+
114+
if (document.readyState === 'loading') {
115+
document.addEventListener('DOMContentLoaded', build, { once: true });
116+
} else {
117+
build();
118+
}
119+
})();

user_guide_src/source/changelogs/v4.7.3.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Bugs Fixed
4141
- **Commands:** Fixed a bug in the ``env`` command where passing options only would cause the command to throw a ``TypeError`` instead of showing the current environment.
4242
- **Common:** Fixed a bug where the ``command()`` helper function did not properly clean up output buffers, which could lead to risky tests when exceptions were thrown.
4343
- **Entity:** Fixed a bug where ``Entity::normalizeValue()`` did not handle ``UnitEnum`` before checking for ``toArray()``, causing enums implementing ``toArray()`` to be incorrectly normalized as generic objects instead of enums.
44+
- **Kint:** Fixed a bug where stale Content Security Policy nonces were reused in worker mode, causing browser CSP violations for Debug Toolbar assets.
4445
- **Validation:** Fixed a bug where ``Validation::getValidated()`` dropped fields whose validated value was explicitly ``null``.
4546

4647
See the repo's

user_guide_src/source/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@
111111
# A list of JS files.
112112
html_js_files = [
113113
'js/citheme.js',
114-
'js/carbon.js'
114+
'js/carbon.js',
115+
'js/version_switcher.js'
115116
]
116117

117118
# -- Options for LaTeX output --------------------------------------------------

0 commit comments

Comments
 (0)