1
0
Files
breadcrumb-the-shire/core/Support/helpers/request.php
fs 0e86925464 refactor: rename lib/ to core/ for clearer core-module separation
Rename the top-level lib/ directory to core/ so the project root
immediately communicates which code is core platform and which lives
in modules/. PHP namespaces (MintyPHP\*) are unchanged — only the
Composer PSR-4 path mapping moves from lib/ to core/.

Module-internal lib/ directories (modules/*/lib/) are untouched.

Updated across the full stack:
- composer.json PSR-4 mapping
- bootstrap entry points (web/index.php, bin/*, tests/bootstrap.php)
- tooling configs (phpstan.neon, phpunit.xml, php-cs-fixer)
- 26 architecture contract tests
- enforcement-policy, guard-catalog, quality-gates
- all documentation (CLAUDE.md, README, 25 docs/, .agents/skills/)
- bin/qa-extended.sh search paths
- .claude/settings.local.json permission paths

Workflow: .agents/runs/CORE-LIB-RENAME-001/ (Analyst → Planner →
Executor → Code Review (4 findings fixed) → Security Review →
Acceptance Test → Finalizer)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 23:20:42 +02:00

197 lines
5.2 KiB
PHP

<?php
use MintyPHP\Http\Input\FormErrors;
use MintyPHP\Http\Input\RequestInput;
use MintyPHP\Http\Input\RequestInputFactory;
use MintyPHP\Http\Request;
use MintyPHP\Support\Flash;
function requestInput(): RequestInput
{
static $requestInput = null;
if ($requestInput instanceof RequestInput) {
return $requestInput;
}
$factory = app(RequestInputFactory::class);
$requestInput = $factory->create();
return $requestInput;
}
function formErrors(): FormErrors
{
return new FormErrors();
}
function formErrorsFrom(array|FormErrors $errors): FormErrors
{
return formErrors()->merge($errors);
}
function flashFormErrors(FormErrors $errors, ?string $scope = null, string $keyPrefix = 'form_error'): void
{
$index = 0;
foreach ($errors->toFlatList() as $message) {
$key = $keyPrefix . '_' . $index;
Flash::error((string) $message, $scope, $key);
$index++;
}
}
function requestExtractNestedReturnValue(mixed $value): string
{
if (is_string($value)) {
return trim($value);
}
if (!is_array($value)) {
return '';
}
for ($i = count($value) - 1; $i >= 0; $i--) {
$item = $value[$i] ?? null;
if (is_string($item) && trim($item) !== '') {
return trim($item);
}
}
return '';
}
function requestLooksLikeDetailPath(string $path): bool
{
$path = trim($path, '/');
if ($path === '') {
return false;
}
$segments = array_values(array_filter(explode('/', $path), static fn (string $segment): bool => $segment !== ''));
return in_array('edit', $segments, true) || in_array('create', $segments, true);
}
function requestNormalizeSafeInternalTarget(string $target, int $maxDepth = 5): string
{
$target = trim($target);
if ($target === '') {
return '';
}
$parts = parse_url($target);
if (
!is_array($parts)
|| ($parts['scheme'] ?? '') !== ''
|| ($parts['host'] ?? '') !== ''
) {
return '';
}
$safeTarget = Request::safeReturnTarget($target);
if ($safeTarget === '') {
return '';
}
$safeParts = parse_url($safeTarget);
if (!is_array($safeParts)) {
return '';
}
$path = Request::stripLocale(Request::stripBasePath((string) ($safeParts['path'] ?? '')));
if ($path === '') {
return '';
}
$queryParams = [];
parse_str((string) ($safeParts['query'] ?? ''), $queryParams);
if (!is_array($queryParams)) {
$queryParams = [];
}
$nestedReturnTarget = requestExtractNestedReturnValue($queryParams['return'] ?? null);
unset($queryParams['return']);
$query = http_build_query($queryParams);
$normalizedOuterTarget = $path . ($query !== '' ? '?' . $query : '');
if ($maxDepth > 0 && $nestedReturnTarget !== '' && requestLooksLikeDetailPath($path)) {
$resolvedNestedTarget = requestNormalizeSafeInternalTarget($nestedReturnTarget, $maxDepth - 1);
if ($resolvedNestedTarget !== '') {
return $resolvedNestedTarget;
}
}
return $normalizedOuterTarget;
}
function requestResolveReturnTargetFromInput(RequestInput $input, string $fallback = ''): string
{
$normalizedFallback = requestNormalizeSafeInternalTarget($fallback);
$candidate = $input->body('return', '');
if (!is_string($candidate)) {
$candidate = '';
}
$candidate = trim($candidate);
if ($candidate === '') {
$candidate = $input->query('return', '');
if (!is_string($candidate)) {
$candidate = '';
}
$candidate = trim($candidate);
}
if ($candidate !== '') {
$resolved = requestNormalizeSafeInternalTarget($candidate);
if ($resolved !== '') {
if ($normalizedFallback === '') {
return $resolved;
}
$resolvedPath = (string) parse_url($resolved, PHP_URL_PATH);
if ($resolvedPath !== '' && !requestLooksLikeDetailPath($resolvedPath)) {
return $resolved;
}
}
}
return $normalizedFallback;
}
function requestResolveReturnTarget(string $fallback = ''): string
{
return requestResolveReturnTargetFromInput(requestInput(), $fallback);
}
function requestPathWithReturnTarget(string $path, string $returnTarget = ''): string
{
$resolvedPath = requestNormalizeSafeInternalTarget($path);
if ($resolvedPath === '') {
return '';
}
$returnTarget = trim($returnTarget);
if ($returnTarget === '') {
return $resolvedPath;
}
$normalizedReturnTarget = requestNormalizeSafeInternalTarget($returnTarget);
if ($normalizedReturnTarget === '') {
return $resolvedPath;
}
$parts = parse_url($resolvedPath);
if (!is_array($parts)) {
return '';
}
$pathValue = Request::stripLocale(Request::stripBasePath((string) ($parts['path'] ?? '')));
if ($pathValue === '') {
return '';
}
$queryParams = [];
parse_str((string) ($parts['query'] ?? ''), $queryParams);
if (!is_array($queryParams)) {
$queryParams = [];
}
unset($queryParams['return']);
$queryParams['return'] = $normalizedReturnTarget;
$query = http_build_query($queryParams);
return $pathValue . ($query !== '' ? '?' . $query : '');
}