diff --git a/demos/_includes/ReloadTest.php b/demos/_includes/ReloadTest.php index 2688854f4a..3f3f9ed315 100644 --- a/demos/_includes/ReloadTest.php +++ b/demos/_includes/ReloadTest.php @@ -17,7 +17,7 @@ protected function init(): void $label = Label::addTo($this, ['Testing...', 'detail' => '', 'class.red' => true]); $reload = new JsReload($this, [$this->name => 'ok']); - if (isset($_GET[$this->name])) { + if ($this->getApp()->hasRequestQueryParam($this->name)) { $label->class[] = 'green'; $label->content = 'Reload success'; } else { diff --git a/demos/_includes/ViewTester.php b/demos/_includes/ViewTester.php index 237577aec0..b21c989f73 100644 --- a/demos/_includes/ViewTester.php +++ b/demos/_includes/ViewTester.php @@ -22,7 +22,7 @@ protected function init(): void $label = Label::addTo($this, ['CallBack', 'detail' => 'fail', 'class.red' => true]); $reload = new JsReload($this, [$this->name => 'ok']); - if (isset($_GET[$this->name])) { + if ($this->getApp()->hasRequestQueryParam($this->name)) { $label->class[] = 'green'; $label->detail = 'success'; } else { diff --git a/demos/_unit-test/callback-nested.php b/demos/_unit-test/callback-nested.php index 32b0e2d614..3b7cfa86d7 100644 --- a/demos/_unit-test/callback-nested.php +++ b/demos/_unit-test/callback-nested.php @@ -28,7 +28,7 @@ $loader->set(static function (Loader $p) use ($m) { Header::addTo($p, ['Loader-1', 'size' => 4]); - if (isset($_GET['err_main_loader'])) { + if ($p->getApp()->hasRequestQueryParam('err_main_loader')) { throw new Exception('Exception from Main Loader'); } @@ -39,9 +39,9 @@ $loaderSub->set(static function (Loader $p) use ($m) { Header::addTo($p, ['Loader-2', 'size' => 4]); - if (isset($_GET['err_sub_loader'])) { + if ($p->getApp()->hasRequestQueryParam('err_sub_loader')) { throw new Exception('Exception from Sub Loader'); - } elseif (isset($_GET['err_sub_loader2'])) { + } elseif ($p->getApp()->hasRequestQueryParam('err_sub_loader2')) { throw new \Error('Exception II from Sub Loader'); } diff --git a/demos/_unit-test/stream.php b/demos/_unit-test/stream.php index 99e34dcb6e..cface0de2a 100644 --- a/demos/_unit-test/stream.php +++ b/demos/_unit-test/stream.php @@ -128,7 +128,7 @@ public function getMetadata($key = null) } }); -$sizeBytes = $_GET['size_mb'] * 1024 * 1024; +$sizeBytes = (int) $app->getRequestQueryParam('size_mb') * 1024 * 1024; $stream = new $hugePseudoStreamClass(static function (int $pos) { return "\n\0" . str_repeat($pos . ',', 1024); diff --git a/demos/basic/label.php b/demos/basic/label.php index ce9ccd518e..e0815f31e5 100644 --- a/demos/basic/label.php +++ b/demos/basic/label.php @@ -29,7 +29,7 @@ $del = Label::addTo($app, ['Zoe', 'image' => 'https://fomantic-ui.com/images/avatar/small/ade.jpg', 'iconRight' => 'delete']); $del->on('click', '.delete', $del->js()->fadeOut()); -$val = isset($_GET['toggle']) && $_GET['toggle']; +$val = $app->hasRequestQueryParam('toggle') && $app->getRequestQueryParam('toggle'); $toggle = Label::addTo($app, ['icon' => 'toggle ' . ($val ? 'on' : 'off')])->set('Value: ' . $val); $toggle->on('click', new JsReload($toggle, ['toggle' => $val ? null : 1])); diff --git a/demos/collection/multitable.php b/demos/collection/multitable.php index 87a6cab5f7..66d4516ea0 100644 --- a/demos/collection/multitable.php +++ b/demos/collection/multitable.php @@ -32,7 +32,7 @@ public function setModel(Model $model, array $route = []): void $table = Table::addTo($this->addColumn(), ['header' => false, 'class.very basic selectable' => true])->setStyle('cursor', 'pointer'); $table->setModel($model, [$model->titleField]); - $selections = explode(',', $_GET[$this->name] ?? ''); + $selections = explode(',', $this->getApp()->tryGetRequestQueryParam($this->name) ?? ''); if ($selections[0]) { $table->js(true)->find('tr[data-id=' . $selections[0] . ']')->addClass('active'); diff --git a/demos/collection/table.php b/demos/collection/table.php index da920e2f43..7f00ace703 100644 --- a/demos/collection/table.php +++ b/demos/collection/table.php @@ -14,7 +14,7 @@ /** @var \Atk4\Ui\App $app */ require_once __DIR__ . '/../init-app.php'; -if ($_GET['id'] ?? null) { +if ($app->tryGetRequestQueryParam('id')) { $app->layout->js(true, new JsToast('Details link is in simulation mode.')); } diff --git a/demos/form/form3.php b/demos/form/form3.php index 1c27d87bfe..17388df545 100644 --- a/demos/form/form3.php +++ b/demos/form/form3.php @@ -29,7 +29,7 @@ ->on('click', new JsReload($seg, ['m' => 'stat'])); $form = Form::addTo($seg, ['layout' => [Form\Layout\Columns::class]]); -$modelClass = ['country' => Country::class, 'file' => File::class][$_GET['m'] ?? ''] ?? Stat::class; +$modelClass = ['country' => Country::class, 'file' => File::class][$app->tryGetRequestQueryParam('m')] ?? Stat::class; $form->setModel((new $modelClass($app->db))->loadAny()); $form->onSubmit(static function (Form $form) { diff --git a/demos/init-app.php b/demos/init-app.php index 14a99e4137..2dd1b61d8a 100644 --- a/demos/init-app.php +++ b/demos/init-app.php @@ -31,6 +31,23 @@ ]); $app->title = 'Agile UI Demo v' . $app->version; +unset($_SERVER); +unset($_GET); +unset($_POST); +unset($_FILES); +if (isset($_COOKIE)) { // @phpstan-ignore-line https://github.com/phpstan/phpstan/issues/9953 + $sessionCookieName = function_exists('session_name') ? session_name() : false; + foreach (array_keys($_COOKIE) as $k) { + if ($k !== $sessionCookieName) { + unset($_COOKIE[$k]); + } + } + if ($_COOKIE === []) { + unset($_COOKIE); + } +} +unset($_SESSION); + if ($app->callExit !== true) { $app->stickyGet('APP_CALL_EXIT'); } @@ -85,7 +102,7 @@ public static function get_class(\Closure $createAnonymousClassFx): string $demosUrl = $rootUrl . 'demos/'; // allow custom layout override -$app->initLayout([!isset($_GET['layout']) ? Layout\Maestro::class : $app->stickyGet('layout')]); +$app->initLayout([!$app->hasRequestQueryParam('layout') ? Layout\Maestro::class : $app->stickyGet('layout')]); $layout = $app->layout; if ($layout instanceof Layout\NavigableInterface) { diff --git a/demos/interactive/jssortable.php b/demos/interactive/jssortable.php index e2831ae528..f8ddae15d7 100644 --- a/demos/interactive/jssortable.php +++ b/demos/interactive/jssortable.php @@ -36,8 +36,8 @@ $sortable = JsSortable::addTo($view, ['container' => 'ul', 'draggable' => 'li', 'dataLabel' => 'name']); -$sortable->onReorder(static function (array $order, string $src, int $pos, int $oldPos) { - if ($_GET['btn'] ?? null) { +$sortable->onReorder(static function (array $order, string $src, int $pos, int $oldPos) use ($app) { + if ($app->tryGetRequestQueryParam('btn')) { return new JsToast(implode(' - ', $order)); } diff --git a/demos/interactive/loader.php b/demos/interactive/loader.php index bfd03fd8af..6ab11eb240 100644 --- a/demos/interactive/loader.php +++ b/demos/interactive/loader.php @@ -40,7 +40,7 @@ $loader->set(static function (Loader $p) { // you may pass arguments to the loader, in this case it's "color" sleep(1); - $color = $_GET['color']; + $color = $p->getApp()->getRequestQueryParam('color'); Header::addTo($p, ['Loader #1b - ' . $color]); LoremIpsum::addTo(View::addTo($p, ['ui' => $color . ' segment']), ['size' => 1]); diff --git a/demos/interactive/loader2.php b/demos/interactive/loader2.php index d979c65a9e..386e821039 100644 --- a/demos/interactive/loader2.php +++ b/demos/interactive/loader2.php @@ -30,6 +30,6 @@ $countryLoader->set(static function (Loader $p) { Form::addTo($p)->setModel( - (new Country($p->getApp()->db))->load($_GET['id']) + (new Country($p->getApp()->db))->load($p->getApp()->getRequestQueryParam('id')) ); }); diff --git a/demos/interactive/modal.php b/demos/interactive/modal.php index 3ab6602d57..b1178d0134 100644 --- a/demos/interactive/modal.php +++ b/demos/interactive/modal.php @@ -98,7 +98,7 @@ // when $vp2Modal->jsShow() is activate, it will dynamically add this content to it $vp2Modal->set(static function (View $p) use ($vp3Modal) { ViewTester::addTo($p); - Message::addTo($p, [$_GET['color'] ?? 'No color'])->text->addParagraph('This text is loaded using a second modal.'); + Message::addTo($p, [$p->getApp()->tryGetRequestQueryParam('color') ?? 'No color'])->text->addParagraph('This text is loaded using a second modal.'); Button::addTo($p)->set('Third modal') ->on('click', $vp3Modal->jsShow()); }); @@ -179,8 +179,8 @@ $stepModal->set(static function (View $p) use ($session, $previousAction, $nextAction) { $page = $session->recall('page', 1); $success = $session->recall('success', false); - if (isset($_GET['move'])) { - $move = $_GET['move']; + if ($p->getApp()->hasRequestQueryParam('move')) { + $move = $p->getApp()->getRequestQueryParam('move'); if ($move === 'next' && $success) { ++$page; } elseif ($move === 'previous' && $page > 1) { diff --git a/demos/interactive/popup.php b/demos/interactive/popup.php index 584768153a..1db89d70ce 100644 --- a/demos/interactive/popup.php +++ b/demos/interactive/popup.php @@ -52,8 +52,8 @@ protected function init(): void $this->tRow->set('descr', 'click on link to remove item'); // We link to ourselves with this special GET argument to indicate that item must be removed. - if (isset($_GET[$this->name . '_remove'])) { - $this->removeItem($_GET['id']); + if ($this->getApp()->hasRequestQueryParam($this->name . '_remove')) { + $this->removeItem($this->getApp()->getRequestQueryParam('id')); // redirect again, since we don't want this to stay in the URL $this->getApp()->redirect([$this->name . '_remove' => false]); @@ -242,8 +242,8 @@ public function linkCart(View $cart, JsExpressionable $jsAction = null): void $signup->stickyGet('logged'); $signup->set(static function (View $pop) { // content of the popup will be different depending on this condition. - if (isset($_GET['logged'])) { - Message::addTo($pop, ['You are already logged in as ' . $_GET['logged']]); + if ($pop->getApp()->hasRequestQueryParam('logged')) { + Message::addTo($pop, ['You are already logged in as ' . $pop->getApp()->getRequestQueryParam('logged')]); Button::addTo($pop, ['Logout', 'class.primary' => true, 'icon' => 'sign out']) ->link($pop->getApp()->url()); } else { diff --git a/demos/interactive/tabs.php b/demos/interactive/tabs.php index 1eecb740e5..75e216fe72 100644 --- a/demos/interactive/tabs.php +++ b/demos/interactive/tabs.php @@ -35,7 +35,7 @@ // dynamic tab $tabs->addTab('Dynamic Lorem Ipsum', static function (VirtualPage $vp) { Message::addTo($vp, ['Every time you come to this tab, you will see a different text']); - LoremIpsum::addTo($vp, ['size' => (int) ($_GET['size'] ?? 1)]); + LoremIpsum::addTo($vp, ['size' => (int) ($vp->getApp()->tryGetRequestQueryParam('size') ?? 1)]); }, ['apiSettings' => ['data' => ['size' => random_int(1, 4)]]]); // modal tab diff --git a/demos/interactive/virtual.php b/demos/interactive/virtual.php index 2b8abf3be3..03cb4d76b4 100644 --- a/demos/interactive/virtual.php +++ b/demos/interactive/virtual.php @@ -24,8 +24,8 @@ $virtualPage = VirtualPage::addTo($app->layout, ['urlTrigger' => 'in']); // add content to virtual page -if (isset($_GET['p_id'])) { - Header::addTo($virtualPage, [$_GET['p_id']])->addClass('__atk-behat-test-car'); +if ($app->hasRequestQueryParam('p_id')) { + Header::addTo($virtualPage, [$app->getRequestQueryParam('p_id')])->addClass('__atk-behat-test-car'); } LoremIpsum::addTo($virtualPage, ['size' => 1]); $virtualPageButton = Button::addTo($virtualPage, ['Back', 'icon' => 'left arrow']); @@ -74,7 +74,7 @@ Button::addTo($bar)->set('Simulate slow load') ->on('click', new JsModal('My Popup Title', $virtualPage->getJsUrl('cut') . '&slow=true')); -if (isset($_GET['slow'])) { +if ($app->hasRequestQueryParam('slow')) { sleep(1); } @@ -89,7 +89,7 @@ $frame = VirtualPage::addTo($app); $frame->set(static function (VirtualPage $p) { - Header::addTo($p, ['Clicked row with ID = ' . ($_GET['id'] ?? '')]); + Header::addTo($p, ['Clicked row with ID = ' . $p->getApp()->tryGetRequestQueryParam('id')]); }); $table->onRowClick(new JsModal('Row Clicked', $frame, ['id' => $table->jsRow()->data('id')])); diff --git a/demos/interactive/wizard.php b/demos/interactive/wizard.php index 319971e91b..b6d69d1ca4 100644 --- a/demos/interactive/wizard.php +++ b/demos/interactive/wizard.php @@ -47,8 +47,8 @@ // and set a custom JS action or even set a different link. You can use recall() // to access some values that were recorded on another steps. $wizard->addStep(['Select Model', 'description' => '"Country" or "Stat"', 'icon' => 'table'], static function (Wizard $wizard) { - if (isset($_GET['name'])) { - $wizard->memorize('model', $_GET['name']); + if ($wizard->getApp()->hasRequestQueryParam('name')) { + $wizard->memorize('model', $wizard->getApp()->getRequestQueryParam('name')); $wizard->getApp()->redirect($wizard->urlNext()); } diff --git a/demos/javascript/js.php b/demos/javascript/js.php index b1ac81267d..fff275d3db 100644 --- a/demos/javascript/js.php +++ b/demos/javascript/js.php @@ -30,7 +30,7 @@ Button::addTo($app, ['Redirect']) ->on('click', null, $app->jsRedirect(['foo' => 'bar'])); -if (isset($_GET['foo']) && $_GET['foo'] === 'bar') { +if ($app->hasRequestQueryParam('foo') && $app->getRequestQueryParam('foo') === 'bar') { $app->redirect(['foo' => 'baz']); } diff --git a/demos/javascript/reloading.php b/demos/javascript/reloading.php index 1434555805..297bd736df 100644 --- a/demos/javascript/reloading.php +++ b/demos/javascript/reloading.php @@ -50,7 +50,7 @@ // reloading with argument Header::addTo($app, ['We can pass argument to reloader']); -$v = View::addTo($app, ['ui' => 'segment'])->set($_GET['val'] ?? 'No value'); +$v = View::addTo($app, ['ui' => 'segment'])->set($app->tryGetRequestQueryParam('val') ?? 'No value'); Button::addTo($app, ['Set value to "hello"']) ->on('click', new JsReload($v, ['val' => 'hello'])); diff --git a/demos/layout/layout-panel.php b/demos/layout/layout-panel.php index b84dfa063c..d1b45509b3 100644 --- a/demos/layout/layout-panel.php +++ b/demos/layout/layout-panel.php @@ -50,7 +50,7 @@ $view = View::addTo($app, ['ui' => 'segment']); $text = Text::addTo($view); -$text->set($_GET['txt'] ?? 'Not Complete'); +$text->set($app->tryGetRequestQueryParam('txt') ?? 'Not Complete'); $panel1->onOpen(static function (Panel\Content $p) use ($view) { $panel = View::addTo($p, ['ui' => 'basic segment']); diff --git a/demos/others/sticky2.php b/demos/others/sticky2.php index 2d8fb02e20..6a7167c4b5 100644 --- a/demos/others/sticky2.php +++ b/demos/others/sticky2.php @@ -19,14 +19,14 @@ // This demo shows a local impact of a sticky parameters -if (isset($_GET['name'])) { +if ($app->hasRequestQueryParam('name')) { // IMPORTANT: because this is an optional frame, I have to specify it's unique shortName explicitly, othrewise // the name for a second frame will be affected by presence of GET['name'] parameter $frame = View::addTo($app, ['ui' => 'red segment', 'shortName' => 'fr1']); $frame->stickyGet('name'); // frame will generate URL with sticky parameter - Label::addTo($frame, ['Name:', 'detail' => $_GET['name'], 'class.black' => true])->link($frame->url()); + Label::addTo($frame, ['Name:', 'detail' => $app->getRequestQueryParam('name'), 'class.black' => true])->link($frame->url()); // app still generates URL without localized sticky Label::addTo($frame, ['Reset', 'iconRight' => 'close', 'class.black' => true])->link($app->url()); @@ -34,14 +34,14 @@ // nested interactive elements will respect lockal sticky get Button::addTo($frame, ['Triggering callback here will inherit color']) - ->on('click', static function () { - return new JsToast('Color was = ' . $_GET['name']); + ->on('click', static function () use ($app) { + return new JsToast('Color was = ' . $app->getRequestQueryParam('name')); }); // next we have loader, which will dynamically load console which will dynamically output "success" message Loader::addTo($frame)->set(static function (Loader $p) { Console::addTo($p)->set(static function (Console $console) { - $console->output('success!, color is still ' . $_GET['name']); + $console->output('success!, color is still ' . $console->getApp()->getRequestQueryParam('name')); }); }); } @@ -53,7 +53,7 @@ $frame = View::addTo($app, ['ui' => 'green segment']); Button::addTo($frame, ['does not inherit sticky get']) ->on('click', static function () use ($app) { - return new JsToast('$_GET = ' . $app->encodeJson($_GET)); + return new JsToast('$_GET = ' . $app->encodeJson($app->getRequest()->getQueryParams())); }); Header::addTo($app, ['Use of View::url()']); diff --git a/demos/tutorial/intro.php b/demos/tutorial/intro.php index ec3cf7b06e..55ff31b8a8 100644 --- a/demos/tutorial/intro.php +++ b/demos/tutorial/intro.php @@ -94,7 +94,7 @@ View::addTo($seg, ['ui' => 'divider']); - $count = $_GET['count'] ?? 1; + $count = $seg->getApp()->tryGetRequestQueryParam('count') ?? 1; for ($i = 1; $i <= $count; ++$i) { Button::addTo($seg, [(string) $i]); } diff --git a/docs/app.md b/docs/app.md index a9fa2c2dde..5c1c9d9a86 100644 --- a/docs/app.md +++ b/docs/app.md @@ -268,12 +268,12 @@ to provide a simple way to redirect for users who are not familiar with JavaScri so well. Example: ``` -if (!isset($_GET['age'])) { +if (!$app->hasRequestQueryParam('age')) { $app->redirect(['age' => 18]); } Button::addTo($app, ['Increase age']) - ->on('click', $app->jsRedirect(['age' => $_GET['age'] + 1])); + ->on('click', $app->jsRedirect(['age' => $app->getRequestQueryParam('age') + 1])); ``` No much magic in these methods. diff --git a/docs/core.md b/docs/core.md index cf7bb12f98..66144ced30 100644 --- a/docs/core.md +++ b/docs/core.md @@ -81,8 +81,8 @@ Agile UI implements advanced approach allowing any View object that you add into declare "sticky GET arguments". Here is example: ``` -if (isset($_GET['message'])) { - Message::addTo($app)->set($_GET['message']); +if ($app->hasRequestQueryParam('message')) { + Message::addTo($app)->set($app->getRequestQueryParam('message')); } Button::addTo($app, ['Trigger message'])->link(['message' => 'Hello World']); @@ -96,7 +96,7 @@ In Agile UI you can request that some $_GET arguments are preserved and included ``` if ($this->getApp()->stickyGet('message')) { - Message::addTo($app)->set($_GET['message']); + Message::addTo($app)->set($app->getRequestQueryParam('message')); } Button::addTo($app, ['Trigger message'])->link(['message' => 'Hello World']); diff --git a/docs/js.md b/docs/js.md index 7875c504f2..f57b5eb61e 100644 --- a/docs/js.md +++ b/docs/js.md @@ -216,7 +216,7 @@ The following code is safe: ``` $b = new Button(); -$b->js(true)->text($_GET['button_text']); +$b->js(true)->text($app->getRequestQueryParam('button_text')); ``` Any malicious input through the GET arguments will be encoded as JS string before being included as an diff --git a/docs/quickstart.md b/docs/quickstart.md index b79608fff5..0a579646ad 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -256,8 +256,8 @@ $grid->menu->addItem('Complete Selected', ]) ); -if (isset($_GET['delete'])) { - foreach (explode(',', $_GET['delete']) as $id) { +if ($app->hasRequestQueryParam('delete')) { + foreach (explode(',', $app->getRequestQueryParam('delete')) as $id) { $grid->model->delete($id); } } diff --git a/docs/render.md b/docs/render.md index d14ba3c43a..1b473b7ede 100644 --- a/docs/render.md +++ b/docs/render.md @@ -133,11 +133,11 @@ class MyView extends View { parent::init(); - if ($_GET[$this->name]) { + if ($this->getApp()->getRequestQueryParam($this->name)) { \Atk4\Ui\Label::addTo($this, [ 'Secret info is', 'class.big red' => true, - 'detail' => $_GET[$this->name], + 'detail' => $this->getApp()->getRequestQueryParam($this->name), ]); } diff --git a/docs/rightpanel.md b/docs/rightpanel.md index ef917ed650..ad631fae57 100644 --- a/docs/rightpanel.md +++ b/docs/rightpanel.md @@ -50,7 +50,7 @@ $button->js(true)->data('btn', '1'); $button->on('click', $panel->jsOpen(['btn'], 'orange')); $panel->onOpen(function (Panel\Content $p) { - $buttonNumber = $_GET['btn'] ?? null; + $buttonNumber = $p->getApp()->tryGetRequestQueryParam('btn'); $text = 'You loaded panel content using button #' . $buttonNumber; Message::addTo($p, ['Panel 1', 'text' => $text]); }); diff --git a/docs/sticky.md b/docs/sticky.md index a18d73ac47..f70204f375 100644 --- a/docs/sticky.md +++ b/docs/sticky.md @@ -31,7 +31,7 @@ $app->stickyGet('client_id'); Loader::addTo($app)->set(function (Loader $p) { Console::addTo($p)->set(function (Console $console) { - $console->output('client_id = !' . $_GET['client_id']); + $console->output('client_id = !' . $console->getApp()->getRequestQueryParam('client_id')); }); }); ``` diff --git a/phpstan.neon.dist b/phpstan.neon.dist index df112c68cf..9cc5f15834 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -16,6 +16,12 @@ parameters: - '~^Only booleans are allowed in .+, .+ given( on the (left|right) side)?\.~' - '~^Variable (static )?(property access|method call) on .+\.~' + # https://github.com/phpstan/phpstan/issues/9951 + - + path: 'src/Table/Column/FilterModel/Type*.php' + message: '~^Parameter (#2 \$operator|#3 \$value) of method Atk4\\Data\\Model::addCondition\(\) expects (Atk4\\Data\\Persistence\\Sql\\Expressionable\|string, bool|string, DateTime) given\.$~' + count: 5 + # TODO these rules are generated, this ignores should be fixed in the code # for level = 2 - diff --git a/src/App.php b/src/App.php index efc41481f9..9430a83367 100644 --- a/src/App.php +++ b/src/App.php @@ -26,6 +26,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UploadedFileInterface; use Psr\Log\LoggerInterface; class App @@ -300,7 +301,7 @@ public function caughtException(\Throwable $exception): void $this->layout->template->tryDel('Header'); if (($this->isJsUrlRequest() || $this->getRequest()->getHeaderLine('X-Requested-With') === 'XMLHttpRequest') - && !isset($_GET['__atk_tab'])) { + && !$this->hasRequestQueryParam('__atk_tab')) { $this->outputResponseJson([ 'success' => false, 'message' => $this->layout->getHtml(), @@ -320,6 +321,98 @@ public function getRequest(): ServerRequestInterface return $this->request; } + /** + * Check if a specific GET parameter exists in the HTTP request. + */ + public function hasRequestQueryParam(string $key): bool + { + return $this->tryGetRequestQueryParam($key) !== null; + } + + /** + * Try to get the value of a specific GET parameter from the HTTP request. + */ + public function tryGetRequestQueryParam(string $key): ?string + { + return $this->getRequest()->getQueryParams()[$key] ?? null; + } + + /** + * Get the value of a specific GET parameter from the HTTP request. + */ + public function getRequestQueryParam(string $key): string + { + $res = $this->tryGetRequestQueryParam($key); + if ($res === null) { + throw (new Exception('GET param does not exist')) + ->addMoreInfo('key', $key); + } + + return $res; + } + + /** + * Check if a specific POST parameter exists in the HTTP request. + */ + public function hasRequestPostParam(string $key): bool + { + return $this->tryGetRequestPostParam($key) !== null; + } + + /** + * Try to get the value of a specific POST parameter from the HTTP request. + */ + public function tryGetRequestPostParam(string $key): ?string + { + return $this->getRequest()->getParsedBody()[$key] ?? null; + } + + /** + * Get the value of a specific POST parameter from the HTTP request. + * + * @return mixed + */ + public function getRequestPostParam(string $key) + { + $res = $this->tryGetRequestPostParam($key); + if ($res === null) { + throw (new Exception('POST param does not exist')) + ->addMoreInfo('key', $key); + } + + return $res; + } + + /** + * Check if a specific uploaded file exists in the HTTP request. + */ + public function hasRequestUploadedFile(string $key): bool + { + return $this->tryGetRequestUploadedFile($key) !== null; + } + + /** + * Try to get a specific uploaded file from the HTTP request. + */ + public function tryGetRequestUploadedFile(string $key): ?UploadedFileInterface + { + return $this->getRequest()->getUploadedFiles()[$key] ?? null; + } + + /** + * Get a specific uploaded file from the HTTP request. + */ + public function getRequestUploadedFile(string $key): UploadedFileInterface + { + $res = $this->tryGetRequestUploadedFile($key); + if ($res === null) { + throw (new Exception('FILES upload does not exist')) + ->addMoreInfo('key', $key); + } + + return $res; + } + public function getResponse(): ResponseInterface { return $this->response; @@ -398,7 +491,7 @@ public function terminate($output = ''): void } $this->outputResponseJson($output); - } elseif (isset($_GET['__atk_tab']) && $type === 'text/html') { + } elseif ($this->hasRequestQueryParam('__atk_tab') && $type === 'text/html') { $output = $this->getTag('script', [], '$(function () {' . $output['atkjs'] . '});') . $output['html']; @@ -549,9 +642,9 @@ public function run(): void $this->html->template->dangerouslyAppendHtml('Head', $this->getTag('script', [], '$(function () {' . $this->html->getJs() . ';});')); $this->isRendering = false; - if (isset($_GET[Callback::URL_QUERY_TARGET]) && $this->catchRunawayCallbacks) { + if ($this->hasRequestQueryParam(Callback::URL_QUERY_TARGET) && $this->catchRunawayCallbacks) { throw (new Exception('Callback requested, but never reached. You may be missing some arguments in request URL.')) - ->addMoreInfo('callback', $_GET[Callback::URL_QUERY_TARGET]); + ->addMoreInfo('callback', $this->getRequestQueryParam(Callback::URL_QUERY_TARGET)); } $output = $this->html->template->renderToHtml(); @@ -637,7 +730,7 @@ public function stickyGet(string $name, bool $isDeleting = false): ?string { $this->stickyGetArguments[$name] = !$isDeleting; - return $_GET[$name] ?? null; + return $this->tryGetRequestQueryParam($name); } /** @@ -723,7 +816,7 @@ public function jsUrl($page = [], array $extraRequestUrlArgs = []): string */ public function isJsUrlRequest(): bool { - return isset($_GET['__atk_json']) && $_GET['__atk_json'] !== '0'; + return $this->hasRequestQueryParam('__atk_json') && $this->getRequestQueryParam('__atk_json') !== '0'; } /** @@ -1028,8 +1121,6 @@ function () { ); } - // RESPONSES - /** * @internal should be called only from self::outputResponse() and self::outputLateOutputError() */ diff --git a/src/Callback.php b/src/Callback.php index 665d0b1ca2..e1476ed86c 100644 --- a/src/Callback.php +++ b/src/Callback.php @@ -99,12 +99,12 @@ public function terminateJson(View $view): void */ public function isTriggered(): bool { - return isset($_GET[self::URL_QUERY_TRIGGER_PREFIX . $this->urlTrigger]); + return $this->getApp()->hasRequestQueryParam(self::URL_QUERY_TRIGGER_PREFIX . $this->urlTrigger); } public function getTriggeredValue(): string { - return $_GET[self::URL_QUERY_TRIGGER_PREFIX . $this->urlTrigger]; + return $this->getApp()->tryGetRequestQueryParam(self::URL_QUERY_TRIGGER_PREFIX . $this->urlTrigger) ?? ''; } /** @@ -112,7 +112,7 @@ public function getTriggeredValue(): string */ public function canTerminate(): bool { - return isset($_GET[self::URL_QUERY_TARGET]) && $_GET[self::URL_QUERY_TARGET] === $this->urlTrigger; + return $this->getApp()->hasRequestQueryParam(self::URL_QUERY_TARGET) && $this->getApp()->getRequestQueryParam(self::URL_QUERY_TARGET) === $this->urlTrigger; } /** @@ -120,7 +120,7 @@ public function canTerminate(): bool */ public function canTrigger(): bool { - return $this->triggerOnReload || !isset($_GET['__atk_reload']); + return $this->triggerOnReload || !$this->getApp()->hasRequestQueryParam('__atk_reload'); } /** diff --git a/src/Form.php b/src/Form.php index e5bd4e4317..5182e4f844 100644 --- a/src/Form.php +++ b/src/Form.php @@ -436,7 +436,7 @@ public function controlFactory(Field $field, $controlSeed = []): Control */ protected function loadPost(): void { - $postRawData = $_POST; + $postRawData = $this->getApp()->getRequest()->getParsedBody(); $this->hook(self::HOOK_LOAD_POST, [&$postRawData]); $errors = []; diff --git a/src/Form/Control/DropdownCascade.php b/src/Form/Control/DropdownCascade.php index aca27e0743..e6bdacb948 100644 --- a/src/Form/Control/DropdownCascade.php +++ b/src/Form/Control/DropdownCascade.php @@ -30,8 +30,8 @@ protected function init(): void $this->cascadeFrom = $this->form->getControl($this->cascadeFrom); } - $cascadeFromValue = isset($_POST[$this->cascadeFrom->name]) - ? $this->getApp()->uiPersistence->typecastLoadField($this->cascadeFrom->entityField->getField(), $_POST[$this->cascadeFrom->name]) + $cascadeFromValue = $this->getApp()->hasRequestPostParam($this->cascadeFrom->name) + ? $this->getApp()->uiPersistence->typecastLoadField($this->cascadeFrom->entityField->getField(), $this->getApp()->getRequestPostParam($this->cascadeFrom->name)) : $this->cascadeFrom->entityField->get(); $this->model = $this->cascadeFrom->model ? $this->cascadeFrom->model->ref($this->reference) : null; diff --git a/src/Form/Control/Lookup.php b/src/Form/Control/Lookup.php index 4d844ee90f..43d8bd0f48 100644 --- a/src/Form/Control/Lookup.php +++ b/src/Form/Control/Lookup.php @@ -301,7 +301,7 @@ protected function applyLimit($limit = true): void */ protected function applySearchConditions(): void { - $query = $_GET['q'] ?? ''; + $query = $this->getApp()->tryGetRequestQueryParam('q') ?? ''; if ($query === '') { return; } @@ -331,8 +331,8 @@ protected function applyDependencyConditions(): void } $data = []; - if (isset($_GET['form'])) { - parse_str($_GET['form'], $data); + if ($this->getApp()->hasRequestQueryParam('form')) { + parse_str($this->getApp()->getRequestQueryParam('form'), $data); } elseif ($this->form) { $data = $this->form->model->get(); } else { diff --git a/src/Form/Control/Multiline.php b/src/Form/Control/Multiline.php index e337ce122b..ce0eb48934 100644 --- a/src/Form/Control/Multiline.php +++ b/src/Form/Control/Multiline.php @@ -209,7 +209,7 @@ protected function init(): void // load the data associated with this input and validate it $this->form->onHook(Form::HOOK_LOAD_POST, function (Form $form, array &$postRawData) { - $this->rowData = $this->typeCastLoadValues($this->getApp()->decodeJson($_POST[$this->shortName])); + $this->rowData = $this->typeCastLoadValues($this->getApp()->decodeJson($this->getApp()->getRequestPostParam($this->shortName))); if ($this->rowData) { $this->rowErrors = $this->validate($this->rowData); if ($this->rowErrors) { @@ -676,14 +676,14 @@ protected function renderView(): void */ private function outputJson(): void { - switch ($_POST['__atkml_action']) { + switch ($this->getApp()->getRequestPostParam('__atkml_action')) { case 'update-row': $entity = $this->createDummyEntityFromPost($this->model); $expressionValues = array_merge($this->getExpressionValues($entity), $this->getCallbackValues($entity)); $this->getApp()->terminateJson(['success' => true, 'expressions' => $expressionValues]); // no break - expression above always terminate case 'on-change': - $rowsRaw = $this->getApp()->decodeJson($_POST['rows']); + $rowsRaw = $this->getApp()->decodeJson($this->getApp()->getRequestPostParam('rows')); $response = ($this->onChangeFunction)($this->typeCastLoadValues($rowsRaw), $this->form); $this->renderCallback->terminateAjax($this->renderCallback->getAjaxec($response)); // TODO JsCallback::terminateAjax() should return never @@ -727,7 +727,7 @@ private function createDummyEntityFromPost(Model $model): Model $field = $entity->getField($fieldName); - $value = $this->getApp()->uiPersistence->typecastLoadField($field, $_POST[$fieldName]); + $value = $this->getApp()->uiPersistence->typecastLoadField($field, $this->getApp()->getRequestPostParam($fieldName)); if ($field->isEditable()) { try { $field->required = false; diff --git a/src/Form/Control/Upload.php b/src/Form/Control/Upload.php index 7d09e9703b..653a9d50ab 100644 --- a/src/Form/Control/Upload.php +++ b/src/Form/Control/Upload.php @@ -140,19 +140,26 @@ public function addJsAction(JsExpressionable $action): void public function onUpload(\Closure $fx): void { $this->hasUploadCb = true; - if (($_POST['fUploadAction'] ?? null) === self::UPLOAD_ACTION) { + if ($this->getApp()->tryGetRequestPostParam('fUploadAction') === self::UPLOAD_ACTION) { $this->cb->set(function () use ($fx) { $postFiles = []; for ($i = 0;; ++$i) { $k = 'file' . ($i > 0 ? '-' . $i : ''); - if (!isset($_FILES[$k])) { + $uploadFile = $this->getApp()->tryGetRequestUploadedFile($k); + if ($uploadFile === null) { break; } - $postFile = $_FILES[$k]; - if ($postFile['error'] !== 0) { - // unset all details on upload error - $postFile = array_intersect_key($postFile, array_flip(['error', 'name'])); + $postFile = [ + 'name' => $uploadFile->getClientFilename(), + 'error' => $uploadFile->getError(), + ]; + if ($uploadFile->getError() === \UPLOAD_ERR_OK) { + $postFile = array_merge($postFile, [ + 'type' => $uploadFile->getClientMediaType(), + 'tmp_name' => $uploadFile->getStream()->getMetadata('uri'), + 'size' => $uploadFile->getSize(), + ]); } $postFiles[] = $postFile; } @@ -187,9 +194,9 @@ public function onUpload(\Closure $fx): void public function onDelete(\Closure $fx): void { $this->hasDeleteCb = true; - if (($_POST['fUploadAction'] ?? null) === self::DELETE_ACTION) { + if ($this->getApp()->tryGetRequestPostParam('fUploadAction') === self::DELETE_ACTION) { $this->cb->set(function () use ($fx) { - $fileId = $_POST['fUploadId']; + $fileId = $this->getApp()->getRequestPostParam('fUploadId'); $jsRes = $fx($fileId); if ($jsRes !== null) { // @phpstan-ignore-line https://github.com/phpstan/phpstan/issues/9388 @@ -206,7 +213,7 @@ protected function renderView(): void parent::renderView(); if ($this->cb->canTerminate()) { - $uploadActionRaw = $_POST['fUploadAction'] ?? null; + $uploadActionRaw = $this->getApp()->tryGetRequestPostParam('fUploadAction'); if (!$this->hasUploadCb && ($uploadActionRaw === self::UPLOAD_ACTION)) { throw new Exception('Missing onUpload callback'); } elseif (!$this->hasDeleteCb && ($uploadActionRaw === self::DELETE_ACTION)) { diff --git a/src/Grid.php b/src/Grid.php index fc68437079..3f50589aa9 100644 --- a/src/Grid.php +++ b/src/Grid.php @@ -572,7 +572,7 @@ public function addModalBulkAction($item, $title, \Closure $callback, $args = [] */ public function getSortBy(): ?string { - return $_GET[$this->sortTrigger] ?? null; + return $this->getApp()->tryGetRequestQueryParam($this->sortTrigger); } /** diff --git a/src/ItemsPerPageSelector.php b/src/ItemsPerPageSelector.php index 74135fc0f0..e635c39431 100644 --- a/src/ItemsPerPageSelector.php +++ b/src/ItemsPerPageSelector.php @@ -59,7 +59,7 @@ protected function init(): void public function onPageLengthSelect(\Closure $fx): void { $this->cb->set(function () use ($fx) { - $ipp = isset($_GET['ipp']) ? (int) $_GET['ipp'] : null; + $ipp = $this->getApp()->hasRequestQueryParam('ipp') ? (int) $this->getApp()->getRequestQueryParam('ipp') : null; $this->set($this->formatInteger($ipp)); $reload = $fx($ipp); if ($reload) { diff --git a/src/JsCallback.php b/src/JsCallback.php index dd044edb0b..c075268049 100644 --- a/src/JsCallback.php +++ b/src/JsCallback.php @@ -81,7 +81,7 @@ public function set($fx = null, $args = null) $values = []; foreach (array_keys($this->args) as $key) { - $values[] = $_POST[$key]; + $values[] = $this->getApp()->getRequestPostParam($key); } $response = $fx($chain, ...$values); diff --git a/src/JsPaginator.php b/src/JsPaginator.php index c2cad2d1f4..47b2cbe5e8 100644 --- a/src/JsPaginator.php +++ b/src/JsPaginator.php @@ -61,7 +61,7 @@ public function jsIdle(): JsExpressionable */ public function getPage(): int { - return (int) ($_GET['page'] ?? 0); + return (int) ($this->getApp()->tryGetRequestQueryParam('page') ?? 0); } /** diff --git a/src/JsSortable.php b/src/JsSortable.php index 5a5533643d..cdfaa9f343 100644 --- a/src/JsSortable.php +++ b/src/JsSortable.php @@ -68,11 +68,11 @@ protected function init(): void */ public function onReorder(\Closure $fx): void { - $this->set(static function () use ($fx) { - $sortOrders = explode(',', $_POST['order']); - $source = $_POST['source']; - $newIndex = (int) $_POST['newIndex']; - $origIndex = (int) $_POST['origIndex']; + $this->set(function () use ($fx) { + $sortOrders = explode(',', $this->getApp()->getRequestPostParam('order')); + $source = $this->getApp()->getRequestPostParam('source'); + $newIndex = (int) $this->getApp()->getRequestPostParam('newIndex'); + $origIndex = (int) $this->getApp()->getRequestPostParam('origIndex'); return $fx($sortOrders, $source, $newIndex, $origIndex); }); diff --git a/src/JsSse.php b/src/JsSse.php index e03360925e..2d24dfc831 100644 --- a/src/JsSse.php +++ b/src/JsSse.php @@ -35,7 +35,7 @@ protected function init(): void { parent::init(); - if ($_GET['__atk_sse'] ?? null) { + if ($this->getApp()->tryGetRequestQueryParam('__atk_sse')) { $this->browserSupport = true; $this->initSse(); } diff --git a/src/Paginator.php b/src/Paginator.php index 25323240f3..f518015731 100644 --- a/src/Paginator.php +++ b/src/Paginator.php @@ -79,7 +79,7 @@ public function setTotal(int $total): void */ public function getCurrentPage(): int { - return (int) ($_GET[$this->urlTrigger] ?? 1); + return (int) ($this->getApp()->tryGetRequestQueryParam($this->urlTrigger) ?? 1); } /** diff --git a/src/Table/Column/FilterModel.php b/src/Table/Column/FilterModel.php index 8046308452..e12632c6e4 100644 --- a/src/Table/Column/FilterModel.php +++ b/src/Table/Column/FilterModel.php @@ -103,7 +103,7 @@ public function afterInit(): void // create a name for our filter model to save as session data $this->name = 'filter_model_' . $this->lookupField->shortName; - if ($_GET['atk_clear_filter'] ?? false) { + if ($this->getApp()->tryGetRequestQueryParam('atk_clear_filter') ?? false) { $this->forget(); } diff --git a/src/Table/Column/JsHeaderDropdownCallback.php b/src/Table/Column/JsHeaderDropdownCallback.php index cf2ec5271f..2cbc3a5b68 100644 --- a/src/Table/Column/JsHeaderDropdownCallback.php +++ b/src/Table/Column/JsHeaderDropdownCallback.php @@ -17,10 +17,10 @@ class JsHeaderDropdownCallback extends JsCallback */ public function onSelectItem(\Closure $fx): void { - $this->set(static function () use ($fx) { + $this->set(function () use ($fx) { return $fx( - $_GET['id'], - $_GET['item'] + $this->getApp()->getRequestQueryParam('id'), + $this->getApp()->getRequestQueryParam('item') ); }); } diff --git a/src/UserAction/JsCallbackExecutor.php b/src/UserAction/JsCallbackExecutor.php index 4388e15fc6..e96953850c 100644 --- a/src/UserAction/JsCallbackExecutor.php +++ b/src/UserAction/JsCallbackExecutor.php @@ -87,7 +87,7 @@ public function executeModelAction(): void $this->set(function (Jquery $j, ...$values) { $id = $this->getApp()->uiPersistence->typecastLoadField( $this->action->getModel()->getField($this->action->getModel()->idField), - $_POST[$this->name] ?? null + $this->getApp()->tryGetRequestPostParam($this->name) ); if ($id && $this->action->appliesTo === Model\UserAction::APPLIES_TO_SINGLE_RECORD) { if ($this->action->isOwnerEntity() && $this->action->getEntity()->getId()) { diff --git a/src/View.php b/src/View.php index 06344f21b5..8dd2b40fa3 100644 --- a/src/View.php +++ b/src/View.php @@ -518,7 +518,7 @@ protected function _getStickyArgs(): array */ public function stickyGet(string $name, string $newValue = null): ?string { - $this->stickyArgs[$name] = $newValue ?? $this->stickyArgs[$name] ?? $_GET[$name] ?? null; + $this->stickyArgs[$name] = $newValue ?? $this->stickyArgs[$name] ?? $this->getApp()->tryGetRequestQueryParam($name); return $this->stickyArgs[$name]; } @@ -705,7 +705,7 @@ public function renderToJsonArr(): array */ public function getHtml() { - if (isset($_GET['__atk_reload']) && $_GET['__atk_reload'] === $this->name) { + if ($this->getApp()->hasRequestQueryParam('__atk_reload') && $this->getApp()->getRequestQueryParam('__atk_reload') === $this->name) { $this->getApp()->terminateJson($this); } @@ -854,10 +854,10 @@ public function jsGetStoreData(): array { $data = []; $data['local'] = $this->getApp()->decodeJson( - $_GET[$this->name . '_local_store'] ?? $_POST[$this->name . '_local_store'] ?? 'null' + $this->getApp()->tryGetRequestQueryParam($this->name . '_local_store') ?? $this->getApp()->tryGetRequestPostParam($this->name . '_local_store') ?? 'null' ); $data['session'] = $this->getApp()->decodeJson( - $_GET[$this->name . '_session_store'] ?? $_POST[$this->name . '_session_store'] ?? 'null' + $this->getApp()->tryGetRequestQueryParam($this->name . '_session_store') ?? $this->getApp()->tryGetRequestPostParam($this->name . '_session_store') ?? 'null' ); return $data; diff --git a/src/VirtualPage.php b/src/VirtualPage.php index ee778c5033..90a45843ca 100644 --- a/src/VirtualPage.php +++ b/src/VirtualPage.php @@ -100,11 +100,11 @@ public function getHtml() } // render and terminate - if (isset($_GET['__atk_json'])) { + if ($this->getApp()->hasRequestQueryParam('__atk_json')) { $this->getApp()->terminateJson($this); } - if (isset($_GET['__atk_tab'])) { + if ($this->getApp()->hasRequestQueryParam('__atk_tab')) { $this->getApp()->terminateHtml($this->renderToTab()); } diff --git a/src/VueComponent/InlineEdit.php b/src/VueComponent/InlineEdit.php index f2c9d3748a..006e5be3d4 100644 --- a/src/VueComponent/InlineEdit.php +++ b/src/VueComponent/InlineEdit.php @@ -96,7 +96,7 @@ public function setModel(Model $entity): void if ($this->autoSave && $this->model->isLoaded()) { $this->cb->set(function () { - $postValue = $_POST['value']; + $postValue = $this->getApp()->getRequestPostParam('value'); try { $this->model->set($this->fieldName, $this->getApp()->uiPersistence->typecastLoadField($this->model->getField($this->fieldName), $postValue)); $this->model->save(); @@ -125,7 +125,7 @@ public function onChange(\Closure $fx): void if (!$this->autoSave) { $value = $this->getApp()->uiPersistence->typecastLoadField( $this->model->getField($this->fieldName), - $_POST['value'] ?? null + $this->getApp()->tryGetRequestPostParam('value') ); $this->cb->set(static function () use ($fx, $value) { return $fx($value); diff --git a/src/VueComponent/ItemSearch.php b/src/VueComponent/ItemSearch.php index 9467a6b9ba..2e342d67e2 100644 --- a/src/VueComponent/ItemSearch.php +++ b/src/VueComponent/ItemSearch.php @@ -60,7 +60,7 @@ protected function init(): void */ public function getQuery() { - return $_GET[$this->queryArg] ?? null; + return $this->getApp()->tryGetRequestQueryParam($this->queryArg) ?? ''; } public function setModelCondition(Model $model): void diff --git a/tests/AppTest.php b/tests/AppTest.php index 16f065529b..ac2253952e 100644 --- a/tests/AppTest.php +++ b/tests/AppTest.php @@ -14,6 +14,50 @@ class AppTest extends TestCase { use CreateAppTrait; + public function testHasRequestQueryParam(): void + { + $app = $this->createApp(['request' => (new Psr17Factory())->createServerRequest('GET', '/?a=1&b=0&c=&d')]); + + self::assertTrue($app->hasRequestQueryParam('a')); + self::assertTrue($app->hasRequestQueryParam('b')); + self::assertTrue($app->hasRequestQueryParam('c')); + self::assertTrue($app->hasRequestQueryParam('d')); + self::assertFalse($app->hasRequestQueryParam('z')); + + self::assertSame('1', $app->getRequestQueryParam('a')); + self::assertSame('0', $app->getRequestQueryParam('b')); + self::assertSame('', $app->getRequestQueryParam('c')); + self::assertSame('', $app->getRequestQueryParam('d')); + self::assertNull($app->tryGetRequestQueryParam('z')); + } + + public function testNoRequestQueryParamException(): void + { + $app = $this->createApp(); + + $this->expectException(Exception::class); + $this->expectExceptionMessage('GET param does not exist'); + $app->getRequestQueryParam('foo'); + } + + public function testNoRequestPostParamException(): void + { + $app = $this->createApp(); + + $this->expectException(Exception::class); + $this->expectExceptionMessage('POST param does not exist'); + $app->getRequestPostParam('foo'); + } + + public function testNoRequestUploadedFileException(): void + { + $app = $this->createApp(); + + $this->expectException(Exception::class); + $this->expectExceptionMessage('FILES upload does not exist'); + $app->getRequestUploadedFile('foo'); + } + public function testTemplateClassDefault(): void { $app = $this->createApp(); diff --git a/tests/CreateAppTrait.php b/tests/CreateAppTrait.php index 0d89e97b03..96838eb452 100644 --- a/tests/CreateAppTrait.php +++ b/tests/CreateAppTrait.php @@ -25,8 +25,6 @@ protected function createApp(array $seed = []): App $seed['request'] = (new Psr17Factory())->createServerRequest('GET', '/'); } - $this->setGlobalsFromRequest($seed['request']); - $app = new $appClass(array_merge([ 'catchExceptions' => false, 'alwaysRun' => false, @@ -36,15 +34,6 @@ protected function createApp(array $seed = []): App return $app; } - /** - * TODO remove in https://github.com/atk4/ui/pull/2101. - */ - protected function setGlobalsFromRequest(ServerRequestInterface $request): void - { - $_GET = $request->getQueryParams(); - $_POST = $request->getParsedBody() ?? []; - } - protected function triggerCallback(ServerRequestInterface $request, Callback $cb, string $triggerValue = '1'): ServerRequestInterface { return $request->withQueryParams(array_merge( diff --git a/tests/DemosTest.php b/tests/DemosTest.php index c4dad7156c..b04f9892e6 100644 --- a/tests/DemosTest.php +++ b/tests/DemosTest.php @@ -99,12 +99,15 @@ protected function setSuperglobalsFromRequest(RequestInterface $request): void $requestQuery = $request->getUri()->getQuery(); $_SERVER = [ 'REQUEST_METHOD' => $request->getMethod(), - 'HTTP_HOST' => $request->getUri()->getHost(), 'REQUEST_URI' => $requestPath . ($requestQuery !== '' ? '?' . $requestQuery : ''), 'QUERY_STRING' => $requestQuery, 'DOCUMENT_ROOT' => $rootDirRealpath, 'SCRIPT_FILENAME' => $rootDirRealpath . $requestPath, ]; + foreach (array_keys($request->getHeaders()) as $k) { + $kSever = 'HTTP_' . str_replace('-', '_', strtoupper($k)); + $_SERVER[$kSever] = $request->getHeaderLine($k); + } $_GET = []; parse_str($requestQuery, $queryArr); @@ -169,6 +172,7 @@ protected function getClient(): Client ob_start(); try { $app = $this->createTestingApp(); + $this->resetSuperglobals(); try { require $localPath;