diff --git a/demos/interactive/tabs.php b/demos/interactive/tabs.php index fd0271e3df..97969e158e 100644 --- a/demos/interactive/tabs.php +++ b/demos/interactive/tabs.php @@ -44,7 +44,7 @@ $modelRegister->addField('name', ['caption' => 'Please enter your name (John)']); $form = \Atk4\Ui\Form::addTo($tab, ['segment' => true]); - $form->setModel($modelRegister); + $form->setModel($modelRegister->createEntity()); $form->onSubmit(function (\Atk4\Ui\Form $form) { if ($form->model->get('name') !== 'John') { return $form->error('name', 'Your name is not John! It is "' . $form->model->get('name') . '". It should be John. Pleeease!'); diff --git a/demos/interactive/wizard.php b/demos/interactive/wizard.php index 26192eadef..a1f367073b 100644 --- a/demos/interactive/wizard.php +++ b/demos/interactive/wizard.php @@ -13,7 +13,7 @@ /** * Demonstrates how to use a wizard. */ -$wizard = Wizard::addTo($app, ['stepCallback' => Callback::addTo($app, ['urlTrigger' => 'demo_wizard'])]); +$wizard = Wizard::addTo($app, ['urlTrigger' => 'demo_wizard']); // First step will automatcally be active when you open page first. It // will contain the 'Next' button with a link. $wizard->addStep('Welcome', function (Wizard $wizard) { diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1a132f7d03..bca47766e8 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -904,9 +904,6 @@ parameters: - path: 'src/View.php' message: '~^If condition is always true\.$~' - - - path: 'src/Wizard.php' - message: '~^Negated boolean expression is always false\.$~' - path: 'tests/DemosTest.php' message: '~^Else branch is unreachable because ternary operator condition is always true\.$~' @@ -1201,12 +1198,6 @@ parameters: - path: 'src/AbstractView.php' message: '~^Method Atk4\\Ui\\AbstractView::add\(\) has parameter \$args with no typehint specified\.$~' - - - path: 'src/AbstractView.php' - message: '~^Instanceof between Atk4\\Ui\\View and Atk4\\Ui\\AbstractView will always evaluate to true\.$~' - - - path: 'src/AbstractView.php' - message: '~^Strict comparison using \!\=\= between Atk4\\Ui\\AbstractView and null will always evaluate to true\.$~' - path: 'src/Accordion.php' message: '~^Method Atk4\\Ui\\Accordion::activate\(\) has no return typehint specified\.$~' diff --git a/src/AbstractView.php b/src/AbstractView.php index 769a4334c3..a2e3e7fc4b 100644 --- a/src/AbstractView.php +++ b/src/AbstractView.php @@ -52,7 +52,6 @@ abstract class AbstractView * @var bool */ protected $_rendered = false; - // }}} // {{{ Default init() method and add() logic @@ -119,91 +118,4 @@ public function add($object, $args = null): self return $object; } - - // }}} - - // {{{ Sticky URLs - - /** @var string[] stickyGet arguments */ - public $stickyArgs = []; - - /** - * Build an URL which this view can use for js call-backs. It should - * be guaranteed that requesting returned URL would at some point call - * $this->invokeInit(). - * - * @param array $page - * - * @return string - */ - public function jsUrl($page = []) - { - return $this->getApp()->jsUrl($page, false, $this->_getStickyArgs()); - } - - /** - * Build an URL which this view can use for call-backs. It should - * be guaranteed that requesting returned URL would at some point call - * $this->invokeInit(). - * - * @param string|array $page URL as string or array with page name as first element and other GET arguments - * - * @return string - */ - public function url($page = []) - { - return $this->getApp()->url($page, false, $this->_getStickyArgs()); - } - - /** - * Get sticky arguments defined by the view and parents (including API). - */ - protected function _getStickyArgs(): array - { - if ($this->issetOwner() && $this->getOwner() instanceof self) { - $stickyArgs = array_merge($this->getOwner()->_getStickyArgs(), $this->stickyArgs); - } else { - $stickyArgs = $this->stickyArgs; - } - - /** @var self $childView */ - $childView = $this->mergeStickyArgsFromChildView(); - if ($childView !== null && (!($childView instanceof Callback) || $childView->isTriggered())) { - $alreadyCalled = false; - foreach (debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) { - if ($childView === ($frame['object'] ?? null) && $frame['function'] === '_getStickyArgs') { - $alreadyCalled = true; - } - } - - if (!$alreadyCalled) { - $stickyArgs = array_merge($stickyArgs, $childView->_getStickyArgs()); - } - } - - return $stickyArgs; - } - - protected function mergeStickyArgsFromChildView(): ?self - { - return null; - } - - /** - * Mark GET argument as sticky. Calling url() on this view or any - * sub-views will embedd the value of this GET argument. - * - * If GET argument is empty or false, it won't make into URL. - * - * If GET argument is not presently set you can specify a 2nd argument - * to forge-set the GET argument for current view and it's sub-views. - */ - public function stickyGet(string $name, string $newValue = null): ?string - { - $this->stickyArgs[$name] = $newValue ?? $_GET[$name] ?? null; - - return $this->stickyArgs[$name]; - } - - // }}} } diff --git a/src/App.php b/src/App.php index c770bda688..86404154ee 100644 --- a/src/App.php +++ b/src/App.php @@ -124,6 +124,9 @@ class App 'cache-control' => 'no-store', // disable caching by default ]; + /** @var Modal[] Modal view that need to be rendered using json output. */ + private $modals = []; + /** * @var bool whether or not semantic-ui vue has been initialised */ @@ -222,6 +225,17 @@ static function (int $severity, string $msg, string $file, int $line): bool { $this->executorFactory = Factory::factory([ExecutorFactory::class]); } + /** + * Register a modal view. + * Fomantic-ui Modal are teleported in HTML template + * within specific location. This will keep track + * of modals when terminating app using json. + */ + public function registerModal(Modal $modal): void + { + $this->modals[$modal->short_name] = $modal; + } + public function setExecutorFactory(ExecutorFactory $factory) { $this->executorFactory = $factory; @@ -553,8 +567,9 @@ public function run() $this->is_rendering = false; $this->hook(self::HOOK_BEFORE_OUTPUT); - if (isset($_GET['__atk_callback']) && $this->catch_runaway_callbacks) { - throw new Exception('Callback requested, but never reached. You may be missing some arguments in request URL.'); + if (isset($_GET[Callback::URL_QUERY_TARGET]) && $this->catch_runaway_callbacks) { + throw (new Exception('Callback requested, but never reached. You may be missing some arguments in request URL.')) + ->addMoreInfo('callback', $_GET[Callback::URL_QUERY_TARGET]); } $output = $this->html->template->renderToHtml(); @@ -1132,11 +1147,9 @@ public function getRenderedModals(): array unset($_GET['__atk_reload']); $modals = []; - foreach ($this->html !== null ? $this->html->elements : [] as $view) { - if ($view instanceof Modal) { - $modals[$view->name]['html'] = $view->getHtml(); - $modals[$view->name]['js'] = $view->getJsRenderActions(); - } + foreach ($this->modals as $view) { + $modals[$view->name]['html'] = $view->getHtml(); + $modals[$view->name]['js'] = $view->getJsRenderActions(); } return $modals; diff --git a/src/Callback.php b/src/Callback.php index 9984b5efc8..bfb7a327a8 100644 --- a/src/Callback.php +++ b/src/Callback.php @@ -9,7 +9,7 @@ * executed directly will perform a PHP callback that you set(). * * Callback function run when triggered, i.e. when it's urlTrigger param value is present in the $_GET request. - * The current callback will be set within the $_GET['__atk_callback'] and will be set to urlTrigger as well. + * The current callback will be set within the $_GET[Callback::URL_QUERY_TARGET] and will be set to urlTrigger as well. * * $button = Button::addTo($layout); * $button->set('Click to do something')->link( @@ -22,6 +22,12 @@ */ class Callback extends AbstractView { + /** @const string */ + public const URL_QUERY_TRIGGER_PREFIX = '__atk_cb_'; + + /** @const string */ + public const URL_QUERY_TARGET = '__atk_cbtarget'; + /** @var string Specify a custom GET trigger. */ protected $urlTrigger; @@ -43,6 +49,8 @@ protected function init(): void public function setUrlTrigger(string $trigger = null) { $this->urlTrigger = $trigger ?: $this->name; + + $this->getOwner()->stickyGet(self::URL_QUERY_TRIGGER_PREFIX . $this->urlTrigger); } public function getUrlTrigger(): string @@ -61,13 +69,7 @@ public function getUrlTrigger(): string public function set($fx = null, $args = null) { if ($this->isTriggered() && $this->canTrigger()) { - $this->getApp()->catch_runaway_callbacks = false; - $t = $this->getApp()->run_called; - $this->getApp()->run_called = true; - $ret = $fx(...($args ?? [])); - $this->getApp()->run_called = $t; - - return $ret; + return $fx(...($args ?? [])); } } @@ -86,7 +88,7 @@ public function terminateJson(AbstractView $view): void */ public function isTriggered() { - return isset($_GET[$this->urlTrigger]); + return isset($_GET[self::URL_QUERY_TRIGGER_PREFIX . $this->urlTrigger]); } /** @@ -94,7 +96,7 @@ public function isTriggered() */ public function getTriggeredValue(): string { - return $_GET[$this->urlTrigger] ?? ''; + return $_GET[self::URL_QUERY_TRIGGER_PREFIX . $this->urlTrigger] ?? ''; } /** @@ -102,7 +104,7 @@ public function getTriggeredValue(): string */ public function canTerminate(): bool { - return isset($_GET['__atk_callback']) && $_GET['__atk_callback'] === $this->urlTrigger; + return isset($_GET[self::URL_QUERY_TARGET]) && $_GET[self::URL_QUERY_TARGET] === $this->urlTrigger; } /** @@ -115,12 +117,12 @@ public function canTrigger(): bool /** * Return URL that will trigger action on this call-back. If you intend to request - * the URL direcly in your browser (as iframe, new tab, or document location), you + * the URL directly in your browser (as iframe, new tab, or document location), you * should use getUrl instead. */ public function getJsUrl(string $value = 'ajax'): string { - return $this->jsUrl($this->getUrlArguments($value)); + return $this->getOwner()->jsUrl($this->getUrlArguments($value)); } /** @@ -129,7 +131,7 @@ public function getJsUrl(string $value = 'ajax'): string */ public function getUrl(string $value = 'callback'): string { - return $this->url($this->getUrlArguments($value)); + return $this->getOwner()->url($this->getUrlArguments($value)); } /** @@ -137,14 +139,6 @@ public function getUrl(string $value = 'callback'): string */ private function getUrlArguments(string $value = null): array { - return ['__atk_callback' => $this->urlTrigger, $this->urlTrigger => $value ?? $this->getTriggeredValue()]; - } - - protected function _getStickyArgs(): array - { - // DEV NOTE: - // - getUrlArguments $value used only in https://github.com/atk4/ui/blob/08644a685a9ee07b4e94d1e35e3bd3c95b7a013d/src/VirtualPage.php#L134 - // - $_GET['__atk_callback'] from getUrlArguments seems to control terminating behaviour! - return array_merge(parent::_getStickyArgs(), $this->getUrlArguments() /* TODO we do not want/need all Callback args probably*/); + return [self::URL_QUERY_TARGET => $this->urlTrigger, self::URL_QUERY_TRIGGER_PREFIX . $this->urlTrigger => $value ?? $this->getTriggeredValue()]; } } diff --git a/src/Loader.php b/src/Loader.php index 152ca92677..d8a2b00565 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -116,9 +116,4 @@ public function jsLoad($args = [], $apiConfig = [], $storeName = null) 'storeName' => $storeName ? $storeName : null, ]); } - - protected function mergeStickyArgsFromChildView(): AbstractView - { - return $this->cb; - } } diff --git a/src/Modal.php b/src/Modal.php index fc3437a32e..74d45790e6 100644 --- a/src/Modal.php +++ b/src/Modal.php @@ -59,6 +59,12 @@ class Modal extends View */ public $showActions = false; + protected function init(): void + { + parent::init(); + $this->getApp()->registerModal($this); + } + /** * Set callback function for this modal. * $fx is set as an array in order to comply with View::set(). @@ -330,12 +336,4 @@ protected function renderView(): void parent::renderView(); } - - /** @var AbstractView */ - public $viewForUrl; - - protected function mergeStickyArgsFromChildView(): ?AbstractView - { - return $this->viewForUrl ?? $this->cb; - } } diff --git a/src/Panel/Content.php b/src/Panel/Content.php index 6692fde844..ab28c63405 100644 --- a/src/Panel/Content.php +++ b/src/Panel/Content.php @@ -57,9 +57,4 @@ public function getClearSelector(): array { return ['.atk-panel-content']; } - - protected function mergeStickyArgsFromChildView(): ?\Atk4\Ui\AbstractView - { - return $this->cb; - } } diff --git a/src/Panel/Right.php b/src/Panel/Right.php index 4ca686f256..1d511f792f 100644 --- a/src/Panel/Right.php +++ b/src/Panel/Right.php @@ -202,9 +202,4 @@ protected function renderView(): void $this->js(true, $this->service()->addPanel($this->getPanelOptions())); } - - protected function mergeStickyArgsFromChildView(): ?\Atk4\Ui\AbstractView - { - return $this->dynamicContent; - } } diff --git a/src/Popup.php b/src/Popup.php index 8325e8f3bf..718cf584ef 100644 --- a/src/Popup.php +++ b/src/Popup.php @@ -295,9 +295,4 @@ protected function renderView(): void parent::renderView(); } - - protected function mergeStickyArgsFromChildView(): ?AbstractView - { - return $this->cb; - } } diff --git a/src/UserAction/ExecutorFactory.php b/src/UserAction/ExecutorFactory.php index 8e8a597514..e65f85e6c8 100644 --- a/src/UserAction/ExecutorFactory.php +++ b/src/UserAction/ExecutorFactory.php @@ -10,7 +10,6 @@ use Atk4\Ui\Button; use Atk4\Ui\Exception; use Atk4\Ui\Item; -use Atk4\Ui\Modal; use Atk4\Ui\View; /** @@ -172,19 +171,7 @@ protected function createExecutor(UserAction $action, View $owner, string $requi } } - $executor = Factory::factory($seed); - if ($executor instanceof Modal) { - // add modal to app->html for proper rendering on callback. - if (!isset($owner->getApp()->html->elements[$executor->short_name])) { - // very dirty hack, @TODO, attach modals in the standard render tree - // but only render the result to a different place/html DOM - $executor->viewForUrl = $owner; - $executor = $owner->getApp()->html->add($executor, 'Modals'); //->setAction($action); - } - } else { - $executor = $owner->add($executor); - } - + $executor = $owner->add(Factory::factory($seed)); $executor->setAction($action); return $executor; diff --git a/src/View.php b/src/View.php index bde56a4a3d..174036890f 100644 --- a/src/View.php +++ b/src/View.php @@ -40,7 +40,7 @@ class View extends AbstractView implements JsExpressionable * * @var string */ - public $region; //'Content'; + public $region; /** * Enables UI keyword for Semantic UI indicating that this is a @@ -122,7 +122,6 @@ class View extends AbstractView implements JsExpressionable /** @var ExecutorFactory Seed class name */ public $executorFactory; - // }}} // {{{ Setting Things up @@ -584,6 +583,71 @@ public function removeAttr($property) // }}} + // {{{ Sticky URLs + + /** @var string[] stickyGet arguments */ + public $stickyArgs = []; + + /** + * Build an URL which this view can use for js call-backs. It should + * be guaranteed that requesting returned URL would at some point call + * $this->invokeInit(). + * + * @param array $page + * + * @return string + */ + public function jsUrl($page = []) + { + return $this->getApp()->jsUrl($page, false, $this->_getStickyArgs()); + } + + /** + * Build an URL which this view can use for call-backs. It should + * be guaranteed that requesting returned URL would at some point call + * $this->invokeInit(). + * + * @param string|array $page URL as string or array with page name as first element and other GET arguments + * + * @return string + */ + public function url($page = []) + { + return $this->getApp()->url($page, false, $this->_getStickyArgs()); + } + + /** + * Get sticky arguments defined by the view and parents (including API). + */ + protected function _getStickyArgs(): array + { + if ($this->issetOwner() && $this->getOwner() instanceof self) { + $stickyArgs = array_merge($this->getOwner()->_getStickyArgs(), $this->stickyArgs); + } else { + $stickyArgs = $this->stickyArgs; + } + + return $stickyArgs; + } + + /** + * Mark GET argument as sticky. Calling url() on this view or any + * sub-views will embedd the value of this GET argument. + * + * If GET argument is empty or false, it won't make into URL. + * + * If GET argument is not presently set you can specify a 2nd argument + * to forge-set the GET argument for current view and it's sub-views. + */ + public function stickyGet(string $name, string $newValue = null): ?string + { + $this->stickyArgs[$name] = $newValue ?? $_GET[$name] ?? null; + + return $this->stickyArgs[$name]; + } + + // }}} + // {{{ Rendering /** diff --git a/src/VirtualPage.php b/src/VirtualPage.php index c95c952d41..c111b964dd 100644 --- a/src/VirtualPage.php +++ b/src/VirtualPage.php @@ -150,9 +150,4 @@ public function getHtml() $this->getApp()->terminateHtml($this->getApp()->html->template); } } - - protected function mergeStickyArgsFromChildView(): AbstractView - { - return $this->cb; - } } diff --git a/src/Wizard.php b/src/Wizard.php index 825cfe0079..8115ee7f7f 100644 --- a/src/Wizard.php +++ b/src/Wizard.php @@ -16,39 +16,19 @@ class Wizard extends View public $defaultTemplate = 'wizard.html'; public $ui = 'steps'; - /** - * Callback, that triggers selection of a step. - * - * @var Callback - */ - public $stepCallback; + /** @var string Get argument for this wizard. */ + public $urlTrigger; - /** - * List of steps. - * - * @var array - */ + /** @var array List of steps. */ public $steps = []; - /** - * Current step. - * - * @var int - */ + /** @var int Current step. */ public $currentStep; - /** - * Button for going to previous step. - * - * @var Button - */ + /** @var Button Button for going to previous step. */ public $buttonPrev; - /** - * Buttor for going to next step. - * - * @var Button - */ + /** @var Button Buttor for going to next step. */ public $buttonNext; /** @@ -65,11 +45,11 @@ protected function init(): void { parent::init(); - if (!$this->stepCallback) { - $this->stepCallback = Callback::addTo($this, ['urlTrigger' => $this->name]); + if (!$this->urlTrigger) { + $this->urlTrigger = $this->name; } - $this->currentStep = (int) ($this->stepCallback->getTriggeredValue() ?: 0); + $this->currentStep = (int) ($this->stickyGet($this->urlTrigger) ?? 0); $this->stepTemplate = $this->template->cloneRegion('Step'); $this->template->del('Step'); @@ -77,24 +57,28 @@ protected function init(): void // add buttons if ($this->currentStep) { $this->buttonPrev = Button::addTo($this, ['Back', 'basic'], ['Left']); - $this->buttonPrev->link($this->stepCallback->getUrl((string) ($this->currentStep - 1))); + $this->buttonPrev->link($this->getUrl($this->currentStep - 1)); } $this->buttonNext = Button::addTo($this, ['Next', 'primary'], ['Right']); $this->buttonFinish = Button::addTo($this, ['Finish', 'primary'], ['Right']); - $this->buttonNext->link($this->stepCallback->getUrl((string) ($this->currentStep + 1))); + $this->buttonNext->link($this->getUrl($this->currentStep + 1)); + } + + protected function getUrl(int $step): string + { + return $this->url([$this->urlTrigger => $step]); } /** * Adds step to the wizard. * - * @param mixed $name Name of tab or Tab object - * @param mixed $callback Optional callback action or URL (or array with url + parameters) + * @param mixed $name Name of tab or Tab object * * @return View */ - public function addStep($name, $callback) + public function addStep($name, \Closure $fx) { $step = Factory::factory([ Step::class, @@ -106,14 +90,9 @@ public function addStep($name, $callback) // add tabs menu item $this->steps[] = $this->add($step, 'Step'); - if (!$this->stepCallback->isTriggered()) { - $_GET[$this->stepCallback->getUrlTrigger()] = '0'; - } - if ($step->sequence === $this->currentStep) { $step->addClass('active'); - - $this->stepCallback->set($callback, [$this]); + $fx($this); } elseif ($step->sequence < $this->currentStep) { $step->addClass('completed'); } @@ -128,20 +107,17 @@ public function addStep($name, $callback) /** * Adds an extra screen to show user when he goes beyond last step. * There won't be "back" button on this step anymore. - * - * @param \Closure $callback Virtual page */ - public function addFinish(\Closure $callback) + public function addFinish(\Closure $fx) { if (count($this->steps) === $this->currentStep + 1) { - $this->buttonFinish->link($this->stepCallback->getUrl((string) (count($this->steps)))); + $this->buttonFinish->link($this->getUrl(count($this->steps))); } elseif ($this->currentStep === count($this->steps)) { $this->buttonPrev->destroy(); $this->buttonNext->addClass('disabled')->set('Completed'); $this->buttonFinish->destroy(); - $this->getApp()->catch_runaway_callbacks = false; - $callback($this); + $fx($this); } else { $this->buttonFinish->destroy(); } @@ -166,12 +142,10 @@ public function add($seed, $region = null): AbstractView /** * Get URL to next step. Will respect stickyGET. - * - * @return string URL to next step */ - public function urlNext() + public function urlNext(): string { - return $this->stepCallback->getUrl((string) ($this->currentStep + 1)); + return $this->getUrl($this->currentStep + 1); } /** @@ -216,9 +190,4 @@ protected function renderView(): void parent::renderView(); } - - protected function mergeStickyArgsFromChildView(): AbstractView - { - return $this->stepCallback; - } } diff --git a/tests/CallbackTest.php b/tests/CallbackTest.php index 3fc37d555a..05774315df 100644 --- a/tests/CallbackTest.php +++ b/tests/CallbackTest.php @@ -5,6 +5,7 @@ namespace Atk4\Ui\Tests; use Atk4\Core\Phpunit\TestCase; +use Atk4\Ui\Callback; class AppMock extends \Atk4\Ui\App { @@ -36,8 +37,10 @@ protected function setUp(): void { $this->app = new AppMock(['always_run' => false, 'catch_exceptions' => false]); $this->app->initLayout([\Atk4\Ui\Layout\Centered::class]); + } - // reset var, between tests + protected function tearDown(): void + { $_GET = []; $_POST = []; } @@ -49,13 +52,46 @@ public function testCallback(): void $cb = \Atk4\Ui\Callback::addTo($this->app); // simulate triggering - $_GET[$cb->name] = '1'; + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . $cb->name] = '1'; $cb->set(function ($x) use (&$var) { $var = $x; }, [34]); $this->assertSame(34, $var); + $this->assertSame('1', $cb->getTriggeredValue()); + } + + public function testCallbackTrigger(): void + { + $cb = \Atk4\Ui\Callback::addTo($this->app); + $this->assertSame($this->app->layout->name . '_' . $cb->short_name, $cb->getUrlTrigger()); + + $cb = Callback::addTo($this->app, ['urlTrigger' => 'test']); + $this->assertSame('test', $cb->getUrlTrigger()); + } + + public function testViewUrlCallback(): void + { + $var = null; + + $v1 = \Atk4\Ui\View::addTo($this->app); + $cb = \Atk4\Ui\Callback::addTo($v1); + + // simulate triggering + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . $cb->name] = '1'; + + $cb->set(function ($x) use (&$var, $v1) { + $v3 = \Atk4\Ui\View::addTo($v1); + $this->assertSame('test.php', $v3->url(['test'])); + $var = $x; + }, [34]); + + $v2 = \Atk4\Ui\View::addTo($v1); + $v2->stickyGet('g1', '1'); + + $this->assertSame(34, $var); + $this->assertSame('test.php?g1=1', $v2->url(['test'])); } public function testCallbackNotFiring(): void @@ -79,7 +115,7 @@ public function testCallbackLater(): void $cb = \Atk4\Ui\CallbackLater::addTo($this->app); // simulate triggering - $_GET[$cb->name] = '1'; + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . $cb->name] = '1'; $cb->set(function ($x) use (&$var) { $var = $x; @@ -100,8 +136,8 @@ public function testCallbackLaterNested(): void $cb = \Atk4\Ui\CallbackLater::addTo($this->app); // simulate triggering - $_GET[$cb->name] = '1'; - $_GET[$cb->name . '_2'] = '1'; + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . $cb->name] = '1'; + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . $cb->name . '_2'] = '1'; $app = $this->app; $cb->set(function ($x) use (&$var, $app, &$cbname) { @@ -146,7 +182,7 @@ public function testVirtualPage(): void $vp = \Atk4\Ui\VirtualPage::addTo($this->app); // simulate triggering - $_GET[$vp->name] = '1'; + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . $vp->name] = '1'; $vp->set(function ($p) use (&$var) { $var = 25; @@ -164,7 +200,7 @@ public function testVirtualPageCustomTrigger(): void $vp = \Atk4\Ui\VirtualPage::addTo($this->app, ['urlTrigger' => 'bah']); // simulate triggering - $_GET['bah'] = '1'; + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . 'bah'] = '1'; $vp->set(function ($p) use (&$var) { $var = 25; @@ -189,7 +225,7 @@ public function testPull230(): void $vp = \Atk4\Ui\VirtualPage::addTo($this->app); // simulate triggering - $_GET[$vp->name] = '1'; + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . $vp->name] = '1'; $vp->set(\Closure::fromCallable([$this, 'callPull230'])); diff --git a/tests/DemosTest.php b/tests/DemosTest.php index 4d7af1891c..c7a5328173 100644 --- a/tests/DemosTest.php +++ b/tests/DemosTest.php @@ -7,6 +7,7 @@ use Atk4\Core\Phpunit\TestCase; use Atk4\Data\Persistence; use Atk4\Ui\App; +use Atk4\Ui\Callback; use GuzzleHttp\Client; use GuzzleHttp\Psr7\Request; use Psr\Http\Message\RequestInterface; @@ -327,7 +328,7 @@ public function testWizard(): void } $response = $this->getResponseFromRequest( - 'interactive/wizard.php?demo_wizard=1&w_form_submit=ajax&__atk_callback=w_form_submit', + 'interactive/wizard.php?demo_wizard=1&' . Callback::URL_QUERY_TRIGGER_PREFIX . 'w_form_submit=ajax&' . Callback::URL_QUERY_TARGET . '=w_form_submit', ['form_params' => [ 'dsn' => 'mysql://root:root@db-host.example.com/atk4', ]] @@ -350,10 +351,10 @@ public function jsonResponseProvider(): array // simple reload $files[] = ['_unit-test/reload.php?__atk_reload=reload']; // loader callback reload - $files[] = ['_unit-test/reload.php?c_reload=ajax&__atk_callback=c_reload']; + $files[] = ['_unit-test/reload.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'c_reload=ajax&' . Callback::URL_QUERY_TARGET . '=c_reload']; // test catch exceptions - $files[] = ['_unit-test/exception.php?m_cb=ajax&__atk_callback=m_cb&__atk_json=1']; - $files[] = ['_unit-test/exception.php?m2_cb=ajax&__atk_callback=m2_cb&__atk_json=1']; + $files[] = ['_unit-test/exception.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'm_cb=ajax&' . Callback::URL_QUERY_TARGET . '=m_cb&__atk_json=1']; + $files[] = ['_unit-test/exception.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'm2_cb=ajax&' . Callback::URL_QUERY_TARGET . '=m2_cb&__atk_json=1']; return $files; } @@ -383,11 +384,11 @@ public function testDemoAssertJsonResponse(string $uri): void public function sseResponseProvider(): array { $files = []; - $files[] = ['_unit-test/sse.php?see_test=ajax&__atk_callback=1&__atk_sse=1']; - $files[] = ['_unit-test/console.php?console_test=ajax&__atk_callback=1&__atk_sse=1']; + $files[] = ['_unit-test/sse.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'see_test=ajax&' . Callback::URL_QUERY_TARGET . '=1&__atk_sse=1']; + $files[] = ['_unit-test/console.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'console_test=ajax&' . Callback::URL_QUERY_TARGET . '=1&__atk_sse=1']; if (!($this instanceof DemosHttpNoExitTest)) { // ignore content type mismatch when App->call_exit equals to true - $files[] = ['_unit-test/console_run.php?console_test=ajax&__atk_callback=1&__atk_sse=1']; - $files[] = ['_unit-test/console_exec.php?console_test=ajax&__atk_callback=1&__atk_sse=1']; + $files[] = ['_unit-test/console_run.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'console_test=ajax&' . Callback::URL_QUERY_TARGET . '=1&__atk_sse=1']; + $files[] = ['_unit-test/console_exec.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'console_test=ajax&' . Callback::URL_QUERY_TARGET . '=1&__atk_sse=1']; } return $files; @@ -433,7 +434,7 @@ public function jsonResponsePostProvider(): array { $files = []; $files[] = [ - '_unit-test/post.php?test_submit=ajax&__atk_callback=test_submit', + '_unit-test/post.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'test_submit=ajax&' . Callback::URL_QUERY_TARGET . '=test_submit', [ 'f1' => 'v1', ], @@ -441,7 +442,7 @@ public function jsonResponsePostProvider(): array // for JsNotify coverage $files[] = [ - 'obsolete/notify2.php?test_notify=ajax&__atk_callback=test_notify', + 'obsolete/notify2.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . 'test_notify=ajax&' . Callback::URL_QUERY_TARGET . '=test_notify', [ 'text' => 'This text will appear in notification', 'icon' => 'warning sign', diff --git a/tests/FormTest.php b/tests/FormTest.php index 2205385982..ab968a129d 100644 --- a/tests/FormTest.php +++ b/tests/FormTest.php @@ -7,6 +7,7 @@ use Atk4\Core\Phpunit\TestCase; use Atk4\Data\Model; use Atk4\Ui\App; +use Atk4\Ui\Callback; use Atk4\Ui\Form; class FormTest extends TestCase @@ -47,8 +48,8 @@ public function assertSubmit(array $post_data, \Closure $submit = null, \Closure $submit_called = false; $_POST = $post_data; // trigger callback - $_GET['atk_submit'] = 'ajax'; - $_GET['__atk_callback'] = 'atk_submit'; + $_GET[Callback::URL_QUERY_TRIGGER_PREFIX . 'atk_submit'] = 'ajax'; + $_GET[Callback::URL_QUERY_TARGET] = 'atk_submit'; $this->f->onSubmit(function (Form $form) use (&$submit_called, $submit) { $submit_called = true;