New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global prefix via route list #1

Open
Sitole opened this Issue Feb 9, 2019 · 9 comments

Comments

Projects
None yet
4 participants
@Sitole
Copy link

Sitole commented Feb 9, 2019

  • bug report? no
  • feature request? yes

Description

Recently, I've created many multi-domain sites and routing was painful.
I think the route list can be the smartest than a simple array of routes and cache.
There's my idea about prefix system.

Before:

$sectionDomain = '//section.example.com/';
$presentationDomain = '//example.com/';

$router = new RouteList;

$router[] = $section = new RouteList('Section');
$router[] = $presentation = new RouteList('Presentation');

// Register presentation home
$presentation[] = new Route($presentationDomain, 'Home:default');

// Register home presenter
$section[] = new Route($sectionDomain, 'Home:default');

// Register login presenter
$section[] = new Route($sectionDomain . 'login', 'Login:fefault');
$section[] = new Route($sectionDomain . 'logout', 'Login:logout');

$section[] = new Route($sectionDomain . 'clanky', 'Articles:default');
$section[] = new Route($sectionDomain . 'novinky', 'News:default');

After:

$router = new RouteList;

$router[] = $section = new RouteList('Section', '//section.example.com/');
$router[] = $presentation = new RouteList('Presentation', '//example.com/');

// Register presentation home
$presentation[] = new Route('', 'Home:default');

// Register home presenter
$section[] = new Route('', 'Home:default');

// Register login presenter
$section[] = new Route('login', 'Login:fefault');
$section[] = new Route('logout', 'Login:logout');

$section[] = new Route('clanky', 'Articles:default');
$section[] = new Route('novinky', 'News:default');
@milo

This comment has been minimized.

Copy link
Member

milo commented Feb 9, 2019

Can be solved now at least in two ways. I'm using following router, when no need to setup different DI container:

<?php

declare(strict_types=1);

namespace App\Routing;

use App\Strict;
use Nette;
use Nette\Application\IRouter;
use Nette\Application\Request;


class DomainRouter implements IRouter
{
	use Strict;

	/** @var IRouter[] */
	private $domains = [];

	/** @var IRouter|null */
	private $matched;


	public function addRouter(string $host, IRouter $router): void
	{
		$this->domains[$host] = $router;
	}


	public function match(Nette\Http\IRequest $httpRequest)
	{
		$host = $httpRequest->getUrl()->getHost();
		$this->matched = $this->domains[$host] ?? null;
		return $this->matched ? $this->matched->match($httpRequest) : null;
	}


	public function constructUrl(Request $appRequest, Nette\Http\Url $refUrl)
	{
		return $this->matched
			? $this->matched->constructUrl($appRequest, $refUrl)
			: null;
	}
}

Usage

$presentation = new RouteList;
$presentation[] = new Route('', 'Home:default');

$section = new RouteList;
$section[] = new Route('', 'Home:default');
$section[] = new Route('login', 'Login:fefault');
$section[] = new Route('logout', 'Login:logout');
$section[] = new Route('clanky', 'Articles:default');
$section[] = new Route('novinky', 'News:default');

$router = new DomainRouter;
$router->addDomain('example.com', $presentation);
$router->addDomain('section.example.com', $section);

And when you need different DI container, setup web server for a different document root with separated index.php and setup DI container with different router factories.

@Sitole

This comment has been minimized.

Copy link
Author

Sitole commented Feb 9, 2019

It looks like a possible solution, but the meaning is different. The list of routers may be a group with specific settings.

Something like:

$params = [
	RouteList::PREFIX => '//section.example.com',
	RouteList::POSTFIX=> '/',
];

$section = new RouteList('Section', $params);

But I do not know if it's for wide use or just for me.
In that case, it does not make sense to add it as new feature.

@dg

This comment has been minimized.

Copy link
Member

dg commented Feb 11, 2019

I want to add to RouteList syntactic sugar similar to forms, ie. instead of

$router = new RouteList();
$router[] = new Route(...);
$router[] = new Route(...);
$router[] = new MyRouter(...);

to allow something like

$router = new RouteList();
$router->addRoute(...);
$router->addRoute(...);
$router->add(new MyRouter...);

Because man don't need to deal with class names so much. And classes can be confusing after merging nette/application#208.

In relation to this issue your code can be written this way:

$router = new RouteList;
$router->withDomain('section.example.com')->withModule('Section')
	->addRoute('', 'Home:default')

	// Register login presenter
	->addRoute('login', 'Login:login')
	->addRoute('logout', 'Login:logout')

	->addRoute('clanky', 'Articles:default')
	->addRoute('novinky', 'News:default');

$router->withDomain('example.com')->withModule('Presentation')
	->addRoute('', 'Home:default');

What do you think?

@Sitole

This comment has been minimized.

Copy link
Author

Sitole commented Feb 11, 2019

It looks perfect. This features are comming in Nette 3/4 or later?

In my opinion setDomain and setModule is better than with*.

@mabar

This comment has been minimized.

Copy link

mabar commented Feb 11, 2019

It's not a typical setter. In that case with* and add* methods return new instances. Also, second call to set* overrides previous call, it's not that case.

@Sitole

This comment has been minimized.

Copy link
Author

Sitole commented Feb 11, 2019

@mabar
My bad. I thought the addRoute method is called on the $router.

@milo

This comment has been minimized.

Copy link
Member

milo commented Feb 11, 2019

👍 The withDomain() will work with patterns, like <foo>.example.com?

@dg

This comment has been minimized.

Copy link
Member

dg commented Feb 11, 2019

Variables like %tld% are important, parameters like <foo> would be useful, but I'm afraid it would complicate the implementation.

@mabar

This comment has been minimized.

Copy link

mabar commented Feb 11, 2019

Could I still use only RouteList and Route? I have own router builder which prefixes all routes with base part and sort them. Requirement to use domain and module routers would complicate that approach.

In route builder configuration could be base uri defined e.g. like

  • <part1>.%sld%.%tld%/<part2>/<part3> (admin.example.com/eshop/eshop-extension)
  • <lang>.%sld%.%tld%/<part1>/<part2>/<part3> (en.example.com/admin/eshop/eshop-extension)

RouteList define just these 3 base parts and nette module, without knowledge about how will base url look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment