custom url router working also in test mode

pn-pm
Member | 20
+
0
-

basically i want to place dynamic urls from posts like /post1-url or even leveled (containing slash) /post2/with/slash-url to router, to be matched against database, and either display content if available, or use next router rule.

I feel there should be a way using $router->match() + routeList if not matched, but did not find out how

So far i fave came up w fn placed in ErrorPresenter startup:

// ErrorPresenter
function startup(){
	$httpRequest = $this->getHttpRequest();
	if(DbPost::exists($httpRequest)){
		$this->forward('Home:viewDbPost', $httpRequest )
	}
}

How can i continue in testing, with Tracy bar on, debug mode to true?
If i put the debugMode to true, I end up in red error page from nette,
and if not, i dont have Tracy bar available.

Possible workaround is, set debug mode in the vieDbPost construct fn again by some cookie, but is it ok?
Second issue is, if done like this, the response also has response code 404, which i dont know how and where to change

Maybe there is some better approach to match dynamic urls?

btw, is there presenterExists() and presenterActionExists() ?
maybe i could direct all urls to one action, and forward, but need to know if presenter and action does match other router rules

Last edited by pn-pm (2023-07-18 14:43)

m.brecher
Generous Backer | 864
+
0
-

@pn-pm

How can i continue in testing, with Tracy bar on, debug mode to true?
If i put the debugMode to true, I end up in red error page from nette,
and if not, i dont have Tracy bar available.

If you want to test real rendering of error page you should set debugMode to true + use special configuration in common.neon file:

application:
	catchExceptions: true

You will have Tracy bar + real error pages

Last edited by m.brecher (2023-07-18 17:38)

m.brecher
Generous Backer | 864
+
0
-

@pn-pm

Maybe there is some better approach to match dynamic urls?

I dont know what exactly mapping url ⇒ database content you want to do. But I had in the past one similar case, where I placed in the same url parameter articles + article categories. In controller I tried first select from database the category and if not exists than select the article. In php this is very simple. In Nette Router unnecessarily complicated. Simply get the parameter from url, pass it to the presenter and in presenter solve matching the right content from the database.

pn-pm
Member | 20
+
-1
-

got it working! info from @m.brecher helped (thank you), in finall state its done like this

application:
	catchExceptions: true

then in ErrorPresenter i changed the response presenter in BadRequesException:

if ($exception instanceof Nette\Application\BadRequestException) {
	[$module, , $sep] = Nette\Application\Helpers::splitName($request->getPresenterName());
	//BEFORE: return new Responses\ForwardResponse($request->setPresenterName($module . $sep . 'Error4xx'));
	return new Responses\ForwardResponse($request->setPresenterName($module . $sep . 'Home'));
}

and finally, in HomePresenter, i have actionDefault to check if article with URL exists

public actionDefault(){
	$httpRequest = $this->getHttpRequest();
	$slug = substr($httpRequest->url->path,1);
	$page = $this->Posts->getByUrl($slug);
	$httpResponse = $this->getHttpResponse();
	if(!empty($page)){
		$httpResponse->setCode(Nette\Http\Response::S200_OK);
		$this->template->pageContent = $page;
		$this->changeAction('viewPage'); // tpl specific for posts
	} else {
		$this->template->pageContent = false; // in template then display 404 msg based on this
		$httpResponse->setCode(Nette\Http\Response::S404_NotFound);
	}
}

One funny thing though, if i test article url /abcd/efgh, TracyBar displays router info to be matching Abcd:efgh but im really in the HomePresenter, where the ErrorPresenter redirected me :D (reason is, last Router Route i have is a classic ‘<presenter>/action’) and is matched, even if such presenter does not exist… any way to fix this?

Btw: is there a way to list all registered Presenters ? like

$this->getPresenters();

Last edited by pn-pm (2023-07-19 12:04)

jeremy
Member | 54
+
+1
-

I'd just simply create a route that automatically sends you to your Home presenter with any URI.

$router->addRoute('<permalink .+>/', [
	'presenter' => 'Home',
	'action' => 'default',
	'permalink' => ''
]);

Leave the Error presenter the way it was before and instead pass actionDefault the permalink parameter.
Then check if the page exists and if not, use $this->error() to send a 404 response.

This is just an example:

public function actionDefault(string $permalink): void {
	$post = $this->Posts->getByUrl($permalink);

	if (empty($post)) {
		$this->error();
	}

	Rest of your code...
}