Custom router with many slugs

2 years ago

dkorpar
Member | 55
+
0
-

So I have a page with >30.000 urls (>10MB of data) and I'm just rewrriting legacy router with new of my own.
Now I come to issue with querying/caching, and none of options looks good to me. When displaying pages if no caching is introduced there's more then 500 queries to database for slugs which is ofcours unnaceptable, and querying all urls is still not a good option, even when cached it's >10MB RAM on each request.

These are my possible options that I'm aware of

  1. Don't use plink macro but output links as href=“/{$product->slug}”

    → currently looks like best option

  2. Cache all possible slugs to array

    → to much RAM usage

  3. Cache url by url

    → to much calls per request to cache storage (redis)

  4. (Legacy way which I'm dropping) having static variable inside router $urlCache that it's filled from anywhere when querying database for product list or category list or whatever.

    → Serious break of OOP, not readable at all and not maintainable.

What do you think/suggest? Stick to #1 option or you know something I'm not aware of at all?

2 years ago

Michal Hlávka
Member | 166
+
0
-

When product entity has it own property slug, where is the problem to use router mask to create url?

Or, can you send me Route from RouteFactory for url, that you want to make? Probably ill be more able to understand.

Last edited by emptywall (2016-10-03 13:13)

2 years ago

dkorpar
Member | 55
+
0
-

I don't know to which presenter this is going in start
I'm querying multiple tables until correct slug is found, so it's not possible to use router mask.
url basically looks like /{$slug}, and this $slug is not neccesary slug from product, it can be either product/category/article, and in AppRoute I get correct presenter/id.

2 years ago

Michal Hlávka
Member | 166
+
0
-

So regardless on stability, in routerfactory you are grabbing slug for example like this mask /<slug>, where it will be decided which presenter belongs to this slug. right?

2 years ago

dkorpar
Member | 55
+
0
-

This is doing AppRoute (implements \Nette\Application\IRouter), in RouterFactory I'm generating RouteList, one of which is AppRoute. AppRoute determines Presenter and id of entity to show (match) based on url, and opposite function constructUrl() which determines url based on presenter name/id

Last edited by dkorpar (2016-10-03 14:22)

2 years ago

Jan Tvrdík
Nette guru | 2547
+
+2
-

Don't use plink macro but output links as href="/{$product->slug}"

Not using routing for seems like the best option to me in this specific case by far.

2 years ago

Tharos
Member | 1041
+
+2
-

+1 for not using plink macro.

Maybe I'd consider generation of one URL via router with some placeholder for slug and after that I'd simply replace that placeholder by real slug as many times as needed.

If you expected some special characters in slug, you could also pass it through exactly the same code (closure or whatever) as in routing. The performance should be still good.

Last edited by Tharos (2016-10-03 15:16)

2 years ago

Jan Mikeš
Member | 771
+
0
-

I like (and use on my own) @Tharos solution, as using simply href="\..., i can see many upsides of this approach for very little perfomance drawback.

2 years ago

dkorpar
Member | 55
+
0
-

So I did something completely different :)
I've change constructUrl function so it actually receives slug instead of id, so I had to change all instances of plink or n:href through templates so it goes like “Presenter:Default, $item->slug” instead of “Presenter:Default, $item->id”, match function remained almost the same…
This way I've got it all covered, but still the problem is that I can't use plink this, any way of resolving that or?
I know it's bnot a perfect solution, but I find it even better then not using plink at all, and performance and querying database is not an issue at all anymore…

2 years ago

dkorpar
Member | 55
+
0
-

To make ‘plink this’ work and not querying db 2X for same thing
(I have to query it in router to actually get presenter and there I get id of item already)
I created class AppRequest extends \Nette\Application\Request and add only one field id to it and in start of presenter I just have
public function renderDefault($id) {
$id = $this->getRequest()->getId();

It is a bit hack, but works nice, adding new parameter to Request would also add it as querystring and I didn't want that, so I implemented it like that…