Skip to content

Commit

Permalink
Presenter: added switch()
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Apr 19, 2024
1 parent 4195243 commit 1573636
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 4 deletions.
34 changes: 31 additions & 3 deletions src/Application/UI/Presenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ abstract class Presenter extends Control implements Application\IPresenter
private ?array $globalStateSinces;
private string $action = '';
private string $view = '';
private bool $forwarded = false;
private string|bool $layout = '';
private \stdClass $payload;
private string $signalReceiver;
Expand Down Expand Up @@ -188,7 +189,14 @@ public function run(Application\Request $request): Application\Response
}

// calls $this->action<Action>()
$this->tryCall(static::formatActionMethod($this->action), $this->params);
try {
actionMethod:
$this->tryCall(static::formatActionMethod($this->action), $this->params);
} catch (Application\SwitchException $e) {
$this->changeAction($e->getMessage());
$this->autoCanonicalize = false;
goto actionMethod;
}

// autoload components
foreach ($this->globalParams as $id => $foo) {
Expand All @@ -211,12 +219,20 @@ public function run(Application\Request $request): Application\Response
$this->beforeRender();
Arrays::invoke($this->onRender, $this);
// calls $this->render<View>()
$this->tryCall(static::formatRenderMethod($this->view), $this->params);
try {
renderMethod:
$this->tryCall(static::formatRenderMethod($this->view), $this->params);
} catch (Application\SwitchException $e) {
$this->setView($e->getMessage());
goto renderMethod;
}
$this->afterRender();

// finish template rendering
$this->sendTemplate();

} catch (Application\SwitchException $e) {
throw new Nette\InvalidStateException('Switch is only supported inside action*() or render*() method.', 0, $e);
} catch (Application\AbortException) {
}

Expand Down Expand Up @@ -327,7 +343,7 @@ public function checkRequirements(\ReflectionClass|\ReflectionMethod $element):
if (
$attribute->forward
&& !$this->request->isMethod($this->request::FORWARD)
&& $this->action === $this->view
&& !$this->forwarded
) {
$this->error('Forwarded request is required by ' . Reflection::toString($element));
}
Expand Down Expand Up @@ -451,10 +467,20 @@ final public function getAction(bool $fullyQualified = false): string
*/
public function changeAction(string $action): void
{
$this->forwarded = true;
$this->action = $this->view = $action;
}


/**
* Switch from current action or render method to another.
*/
public function switch(string $action): never
{
throw new Application\SwitchException($action);
}


/**
* Returns current view.
*/
Expand All @@ -469,6 +495,7 @@ final public function getView(): string
*/
public function setView(string $view): static
{
$this->forwarded = true;
$this->view = $view;
return $this;
}
Expand Down Expand Up @@ -1072,6 +1099,7 @@ private function initGlobalParameters(): void
}

$this->changeAction($action);
$this->forwarded = false;

// init $this->signalReceiver and key 'signal' in appropriate params array
$this->signalReceiver = $this->getUniqueId();
Expand Down
5 changes: 5 additions & 0 deletions src/Application/exceptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ class AbortException extends \LogicException
{
}

/** @internal */
final class SwitchException extends AbortException
{
}


/**
* Application fatal error.
Expand Down
2 changes: 1 addition & 1 deletion tests/UI/LinkGenerator.parseDestination().phpt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

declare(strict_types=1);

use Nette\Application\UI\InvalidLinkException;
use Nette\Application\LinkGenerator;
use Nette\Application\UI\InvalidLinkException;
use Tester\Assert;


Expand Down
29 changes: 29 additions & 0 deletions tests/UI/Requires.forward.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ class TestForwardViewPresenter extends Nette\Application\UI\Presenter
}


class TestSwitchViewPresenter extends Nette\Application\UI\Presenter
{
public function actionDefault(): void
{
$this->switch('forward');
}


#[Requires(forward: true)]
public function actionSwitch(): void
{
$this->terminate();
}
}


// forwarded request
$presenter = createPresenter(TestForwardPresenter::class);
Assert::noError(
Expand All @@ -65,3 +81,16 @@ Assert::exception(
Application\BadRequestException::class,
'Forwarded request is required by TestForwardViewPresenter::renderForward()',
);


// switched view
$presenter = createPresenter(TestSwitchViewPresenter::class);
Assert::noError(
fn() => $presenter->run(new Application\Request('', Http\Request::Get)),
);

Assert::exception(
fn() => $presenter->run(new Application\Request('', Http\Request::Get, ['action' => 'forward'])),
Application\BadRequestException::class,
'Forwarded request is required by TestSwitchViewPresenter::actionSwitch()',
);

0 comments on commit 1573636

Please sign in to comment.