Route Registration
How routes are defined and registered in the application
The Restaurant Menu
Think of routing like a restaurant menu:
- Customer says: "I want pizza"
- Waiter checks the menu: "Pizza → Kitchen Station A"
- Waiter sends order to Station A
In web apps:
- Browser says: "I want GET
/posts" - Router checks routes: "
/posts→posts/index.php" - Router runs that controller file
Where Routes Are Defined
Routes live in routes/routes.php. This is your application's "menu" - the list of all available URLs.
The Global Router
global $router;
$router->get('/', 'welcome.php');What is global $router;?
This is a PHP quirk. Let me explain:
In public/index.php:
$router = new \Core\Router();
require base_path('routes/routes.php');In routes/routes.php:
global $router; // "I want to use the $router from outside"
$router->get('/', 'welcome.php');Why this works:
- When you
requirea file, it runs in the current scope global $routermeans "use the variable that already exists"- So the routes file can call methods on the router object
Is this good?
- ✅ Simple and works
- ❌ "Magic" - beginners might not understand where
$routercomes from - ❌ Not testable (hard to mock)
Better alternatives:
// Option 1: Return routes array
return [
['GET', '/', 'welcome.php'],
['GET', '/posts', 'posts/index.php'],
];
// Option 2: Pass router as parameter
// (requires changing how routes are loaded)But for learning, global is fine and explicit.
Registering Routes
Basic GET Route
$router->get('/', 'welcome.php');What this means:
- Method:
GET - URL:
/ - Controller:
welcome.php
When someone visits http://yoursite.com/, the router will:
- Match this route
- Run
app/Http/controllers/welcome.php
Basic POST Route
$router->post('/login', 'session/store.php');What this means:
- Method:
POST - URL:
/login - Controller:
session/store.php
When a form submits to /login, this controller handles it.
All HTTP Methods
$router->get('/posts', 'posts/index.php'); // View list
$router->post('/posts', 'posts/store.php'); // Create new
$router->patch('/posts/{id}', 'posts/update.php'); // Update
$router->put('/posts/{id}', 'posts/replace.php'); // Replace
$router->delete('/posts/{id}', 'posts/destroy.php'); // DeleteWhy different methods?
- RESTful convention
- Same URL, different actions
- Semantic meaning (GET = read, POST = create, etc.)
Route Parameters
Dynamic Segments
$router->get('/posts/{id}', 'posts/show.php');What {id} means:
- This is a placeholder
- Matches any value in that position
- The value is captured and passed to the controller
Examples:
/posts/1 → matches, id = 1
/posts/42 → matches, id = 42
/posts/hello → matches, id = hello
/posts/ → doesn't match (missing id)
/posts/1/2 → doesn't match (extra segment)Multiple Parameters
$router->get('/users/{userId}/posts/{postId}', 'posts/show.php');Matches:
/users/5/posts/10 → userId = 5, postId = 10Accessing Parameters in Controllers
The router injects parameters into $_GET:
// In posts/show.php controller
$id = $_GET['id'];
$post = $db->query('SELECT * FROM posts WHERE id = :id', [
'id' => $id
])->findOrFail();
view('posts/show.view.php', ['post' => $post]);Why $_GET?
- Familiar to beginners
- No extra abstractions to learn
- Works with existing PHP knowledge
The trade-off:
- ✅ Simple and intuitive
- ❌ Can overwrite real query string params
- ❌ Mixes route params with query params
Attaching Middleware
Protecting Routes
$router->get('/dashboard', 'dashboard/index.php')->only('auth');What ->only('auth') means:
- Before running the controller, run the
authmiddleware - If middleware fails (user not logged in), stop and redirect
- If middleware passes, continue to controller
Multiple Middleware
$router->post('/posts', 'posts/store.php')->only(['auth', 'csrf']);This runs both:
auth- Check if user is logged incsrf- Check if form has valid CSRF token
Guest-Only Routes
$router->get('/login', 'session/create.php')->only('guest');What guest means:
- User must NOT be logged in
- If already logged in, redirect away
- Prevents logged-in users from seeing login page
Method Chaining
Notice the ->only() pattern:
$router->get('/dashboard', 'dashboard/index.php')->only('auth');How this works:
// Inside Router class
public function get($uri, $controller)
{
$this->add('GET', $uri, $controller);
return $this; // ← Returns the router itself
}
public function only($middleware)
{
// Attach middleware to last route
return $this; // ← Returns the router itself
}By returning $this, you can chain methods:
$router
->get('/admin', 'admin/index.php')
->only('auth')
->only('admin'); // Could chain more if neededRoute Order Matters
Important: Routes are checked in order, first match wins.
The Problem
$router->get('/posts/{id}', 'posts/show.php');
$router->get('/posts/create', 'posts/create.php');What happens:
/posts/create → matches first route with id = "create"
Never reaches second route!The Solution
$router->get('/posts/create', 'posts/create.php'); // Specific first
$router->get('/posts/{id}', 'posts/show.php'); // Generic lastRule: More specific routes before more generic routes.
Platform Routes
After your app routes, the platform adds its own:
// Your routes (routes/routes.php)
$router->get('/', 'welcome.php');
$router->get('/posts', 'posts/index.php');
// Platform routes (.dalt/routes/routes.php) - loaded after
$router->get('/learn', 'learn/index.php');
$router->get('/learn/lessons/{lesson}', 'learn/lesson.php');Why this order?
- Your app routes have priority
- Platform routes only add if
.daltexists - No conflicts because platform uses
/learnprefix
Key Takeaways
- Routes are explicit - Every URL must be registered
- Parameters use
{name}syntax - Captured and passed to controllers - Middleware attaches with
->only()- Runs before controllers - Order matters - Specific routes before generic ones
- Method chaining - Clean, readable route definitions
What's Good Here
✅ Simple, readable syntax
✅ Explicit route definitions (no magic)
✅ Middleware is easy to attach
✅ Familiar to Laravel developers
✅ Easy to understand for beginners
Design Note
Advanced routing features like named routes, route groups, and avoiding global $router are intentionally omitted. These add complexity that would obscure the fundamental concept: mapping URLs to controllers. DALT keeps it simple and transparent.
Next, explore the routing internals and pattern matching.