Jak odstraním specifický parametr z url?
- Mardzis
- Člen | 33
Čau, nějakou dobu jsem se snažil vytvořil route který by mi místo ID
zobrazoval název postu, bohužel se mi to nepodařilo nastavit pomocí
routerů, ale pomocí předání dvou parametrů v n:href
, ale
aktuálně mám problém stím, že bych rád přebytečný parametr id z url
vymazal.
- Akutální stav:
/name/23
- Žádaný stav:
/name
Četl jsem kompletní dokumentaci k Router, ale bohužel, jsem to nějak nepobral a menší postrčení by se mi hodilo. + jsem četl také jak už tento problém mnohokrát řešili, ale nejmladší topic byl 3roky starý a byly zde použité metody, které dnešní Nette již nemá.
n:href="Position:show $job->id, $job->url_anchor"
public function renderShow($id, $url_anchor)
{
$job = $this->database->table('jobs_list')->get($id);
if ( ! $job) {
$this->error('Stránka nebyla nalezena');
}
$this->template->job = $job;
}
Aktuální router:
$router[] = new Route('/<url_anchor>/<id>', [
'presenter' => 'Position',
'action' => 'show',
'id' => NULL
]);
Děkuji
Editoval Mardzis (25. 10. 2016 11:56)
- Jan Mikeš
- Člen | 771
Nekombinuj to, buď používej pouze id (a to překládej v routeru pomocí
FILTER_IN + FILTER_OUT na název – to bych ti doporučoval, pokud si nevíš
rady, mohu ti pomoci s implementací) nebo pouze slug (název). Pokud by jsi
z routeru odstranil ID ale stejne ho používal v odkazu, tak se ti budou
generovat url adresy ve tvaru neco/?id=123
takže se ho stejně
nezbavíš.
Editoval Jan Mikeš (25. 10. 2016 12:07)
- Jan Mikeš
- Člen | 771
Než hledat téma pro mě bude jednodušší ti poslat nástřel funkční
implementace ;).
V routeru:
/** @var App\Routing\Sections */
private $sections; // inject pres konstruktor
$appRouter[] = new Route("<sectionId>/", [
"presenter" => "Section",
"action" => "detail",
"sectionId" => [
Route::FILTER_IN => [$this->sections, "sectionSlugToId"],
Route::FILTER_OUT => [$this->sections, "sectionIdToSlug"],
],
]);
App\Routing\Sections:
<?php
namespace App\Routing;
use Nette;
use App\Model\Entities\Section;
use Kdyby\Doctrine\EntityManager;
/**
* @author Jan Mikes <j.mikes@me.com>
* @copyright Jan Mikes - janmikes.cz
*/
final class Sections extends Nette\Object
{
/** @var EntityManager */
private $em;
/** @var [] */
private $sections = NULL;
/** @var [] */
private $sectionsString = NULL;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function sectionSlugToId($slug)
{
if ($this->sectionsString === NULL) {
$this->setupSections();
}
return (empty($this->sectionsString[$slug]) ? NULL : $this->sectionsString[$slug]);
}
public function sectionIdToSlug($id)
{
if ($this->sections === NULL) {
$this->setupSections();
}
return (empty($this->sections[$id]) ? NULL : $this->sections[$id]);
}
private function setupSections()
{
foreach ($this->em->getRepository(Section::class)->findAll() as $section) {
$this->sections[$section->id] = $section->slug;
$this->sectionsString[$section->slug] = $section->id;
}
}
}
Plně funkční ukázka, pracuje se sloupcem slug v tabulce (mám případně i implementace, kde se pracuje bez tohoto sloupce a adresa se generuje vždy za běhu).
Editoval Jan Mikeš (25. 10. 2016 13:06)
- Mardzis
- Člen | 33
Díky, nainstaloval jsem si potřebené knihovny co mi chyběly (Kdyby\Doctrine).
Kódu nejspíš rozumím, jen nevím. První snippet píšeš že by měl
být umístěný v třídě RouterFactory
přímo v funkci
createRouter()
? Píše mi to chybu
Using $this when not in object context
, což je logické protože
ta třída je static. Co chápu špatně?
- Mardzis
- Člen | 33
Vyhazuje mi to chybu, zkoušel jsem promazat cache folder, ale
Method App\Routing\RouterFactory::createRouter() used in service 'routing.router' is not callable.
config.neon
services:
- App\Routing\RouterFactory
router: @App\Routing\RouterFactory::createRouter
RouterFactory.php
namespace App;
use Nette;
use Nette\Application\Routers\RouteList;
use Nette\Application\Routers\Route;
use Nette\Utils\Strings;
class RouterFactory
{
/** @var App\Routing\Sections */
private $sections;
/**
* @return Nette\Application\IRouter
*/
public function createRouter()
{
$router = new RouteList;
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
$router[] = new Route("<id>/", [
"presenter" => "Position",
"action" => "show",
"id" => [
Route::FILTER_IN => [$this->sections, "sectionSlugToId"],
Route::FILTER_OUT => [$this->sections, "sectionIdToSlug"],
],
]);
return $router;
}
}
- Mardzis
- Člen | 33
Změnil jsem construktor na:
function __construct(\App\Routing\Sections $services)
{
$this->sections = $services;
}
a dostávám chybu
Service '67_App_RouterFactory': Service of type App\Routing\Sections needed by App\RouterFactory::__construct() not found. Did you register it in configuration file?
Je potřeba, dle chyby, upravit config, který jsem upravil následovně.
Přidal jsem Sections: App\Routing
je to takto správně?
services:
- App\RouterFactory
router: @App\RouterFactory::createRouter
Sections: App\Routing
- Jan Mikeš
- Člen | 771
Těsně vedle ;). Máš chybu v zápise
Sections: App\Routing
Sections:
je pojmenování služby (může být anonymní a
pojmenovávat nemusíš, pokud to vyloženě nepotřebuješ) a
App\Routing
je třída, která se má pro tuto službu použít.
Správný zápis je tedy
buď
Sections: App\Routing\Sections
Nebo bez názvu služby
- App\Routing\Sections
Editoval Jan Mikeš (26. 10. 2016 17:21)
- Mardzis
- Člen | 33
Po čase sem se ktomu opět dostal, a ano teď už to „funguje“, jen dle tvého příkladu do nedokážu na mém zreplikovat.
Dostávám teď tuto chybu:
Metadata of class App\Model\Entities\Section was not found, because the class is missing or cannot be autoloaded.
Tak nějak okrajově chápu o čem to je, ale nedokážu to replikovat na moje řešení, hledám teď jednoduší řešení kde bych to zatím měl v mém Presenteru a až to lépe pochopím tak se pustím do podobného tomu tvému.
Díky
- Mardzis
- Člen | 33
@JanMikeš Celé jsem to tak nějak přepsal, abych měl oddělený admin a front, podle jistého návodu a ted řeším problém stále stím routováním které mi vůbec nejde do hlavy.
Aktuální RouterFactory.php
<?php
namespace App;
use Nette,
Nette\Application\Routers\RouteList,
Nette\Application\Routers\Route,
Nette\Application\Routers\SimpleRouter;
/**
* Router factory.
*/
class RouterFactory
{
/** @var \PostsRepository */
private $postsRepository;
function __construct(\PostsRepository $postsRepository)
{
$this->postsRepository = $postsRepository;
}
/**
* @return \Nette\Application\IRouter
*/
public function createRouter()
{
$router = new RouteList();
// Admin
$router[] = new Route(
'admin/<presenter>/<action>/<id>', [
'module' => 'Admin',
'presenter' => 'Admin',
'action' => 'default',
'id' => NULL,
]
);
// Front
$router[] = new Route(
'<presenter>/<id>', [
'module' => 'Front',
'presenter' => 'Post',
'action' => 'show',
'id' => [
Route::FILTER_IN => function($url) {
return $url;
},
Route::FILTER_OUT => function($id) {
return $this->postsRepository->getSlugById($id);
}
]
]
);
$router[] = new Route(
'<presenter>/<action>/<id>', [
'module' => 'Front',
'presenter' => 'Homepage',
'action' => 'default',
'id' => NULL,
]
);
return $router;
}
}
Dotazy na id
a slug
public function getSlugById($id)
{
$this->connection->table('posts')
->where('id = ?', $id)
->fetch()->slug;
}
public function getIdBySlug($slug)
{
$this->connection->table('posts')
->where('slug = ?', $slug)
->fetch()->id;
}
Přepis ID by měl vracet $slug
, ale bohužel nic se neděje,
mám defaultní /post/show/3
. Co mi nedochází?
- Jan Mikeš
- Člen | 771
Máš možnost si nainstalovat xdebug a používáš IDE například PhpStorm
nebo Netbeans?
Velmi bych doporučil si to odkrokovat, zjistit jaké parametry funkce dostáva,
jestli se vůbec volá atd.
Pokud debugger nepoužíváš, opravdu doporučuji aby sis to vyzkoušel,
věnoval instalaci a naučení se s ním třeba jedno odpoledne, výsledky a
zlepšení práce pocítíš téměř okamžitě.