DALT.PHP
Framework Deep Dive1. Entry Point

Bootstrap & Routing

How the framework loads itself and routes requests to controllers

Setting Up the Framework

After sessions start, the framework needs to prepare itself. This is called "bootstrapping" - getting ready to handle requests.

Think of it like opening a restaurant:

  • Turn on the lights (load helpers)
  • Prepare the kitchen (set up database)
  • Print the menu (load routes)
  • Open the doors (start accepting requests)

Loading Helper Functions

require BASE_PATH . ('framework/Core/functions.php');

This file defines global helper functions you can use anywhere:

view('welcome.view.php');           // Render a view
redirect('/dashboard');             // Redirect to a URL
abort(404);                         // Stop with an error
csrf_token();                       // Get CSRF token
old('email');                       // Get old form input
base_path('routes/routes.php');     // Get absolute path

Why Global Functions?

These are used so frequently that typing \Core\Helpers::view() would be tedious. Global functions make code cleaner:

// Without helpers
\Core\View::render('welcome.view.php', ['name' => 'Ali']);

// With helpers
view('welcome.view.php', ['name' => 'Ali']);

The Trade-off

Pros:

  • Cleaner, more readable code
  • Faster to type
  • Familiar to Laravel developers

Cons:

  • Can conflict with other libraries
  • Harder to track where functions come from
  • Not namespaced

DALT.PHP chooses convenience here, which is fine for a learning framework.


Bootstrapping the Framework

require base_path('framework/Core/bootstrap.php');

This file does the heavy lifting:

1. Load Environment Variables

$dotenv = Dotenv\Dotenv::createImmutable(base_path(''));
$dotenv->safeLoad();

Reads .env file and fills $_ENV:

DB_DRIVER=sqlite
DB_DATABASE=database/app.sqlite
APP_DEBUG=true

Now you can access: $_ENV['DB_DRIVER']

2. Load Configuration Files

$dbConfig = require base_path('config/database.php');

Config files return arrays:

return [
    'database' => [
        'driver' => $_ENV['DB_DRIVER'] ?? 'sqlite',
        'database' => $_ENV['DB_DATABASE'] ?? 'database/app.sqlite',
    ]
];

3. Create the Dependency Container

$container = new Container();

A container is a "service registry" - a place to store and retrieve shared objects.

Think of it like a toolbox:

  • You put tools in once
  • Anyone can grab them when needed
  • No need to create duplicates

4. Bind the Database

$container->bind('Core\Database', function () use ($dbConfig) {
    return DatabaseManager::create($dbConfig['database']);
});

This says: "When someone asks for Core\Database, run this function to create it."

The database isn't created yet - just the recipe for creating it.

5. Make Container Globally Available

App::setContainer($container);

Now anywhere in your code:

$db = App::resolve(Database::class);

Loading the Platform (Optional)

if (is_dir(base_path('.dalt')) && file_exists(base_path('.dalt/bootstrap.php'))) {
    require base_path('.dalt/bootstrap.php');
}

What is .dalt?

The .dalt folder is the learning platform - the course UI, lessons, and challenges.

Key insight: It's completely optional.

  • If .dalt exists → you get the course at /learn
  • If .dalt is deleted → framework still works perfectly

This separation is brilliant:

  • Core framework is independent
  • Learning features don't pollute the core
  • You can remove .dalt for production

Creating the Router

$router = new \Core\Router();

The router is the "map" from URLs to controllers:

GET /posts        → posts/index.php
GET /posts/10     → posts/show.php
POST /login       → session/store.php

Loading Routes

require base_path('routes/routes.php');

if (is_dir(base_path('.dalt')) && file_exists(base_path('.dalt/routes/routes.php'))) {
    require base_path('.dalt/routes/routes.php');
}

User Routes First

Your app routes are loaded first:

// routes/routes.php
global $router;
$router->get('/', 'welcome.php');
$router->get('/posts', 'posts/index.php');

Platform Routes Second (If Exists)

Then .dalt routes are added:

// .dalt/routes/routes.php
$router->get('/learn', 'learn/index.php');
$router->get('/learn/lessons/{lesson}', 'learn/lesson.php');

This means:

  • Your routes have priority
  • Platform adds its own routes without conflicts
  • Both can coexist

Capturing the Request

$request = Request::capture();

This creates a Request object from PHP superglobals:

// Instead of:
$uri = $_SERVER['REQUEST_URI'];
$method = $_POST['_method'] ?? $_SERVER['REQUEST_METHOD'];
$input = $_POST['email'];

// You can use:
$uri = $request->path();
$method = $request->method();
$input = $request->input('email');

Why Wrap Superglobals?

Benefits:

  • Cleaner API
  • Easier to test (you can mock Request)
  • Handles edge cases (like method spoofing)
  • Type hints work better

Binding Request to Container

App::bind(Request::class, fn () => $request);

Now controllers can get the request:

$request = App::resolve(Request::class);

Routing the Request

$uri = $request->path();
$method = $request->method();

$router->route($uri, $method, $request);

What Happens Inside route()

  1. Loop through registered routes
  2. Match method (GET, POST, etc.)
  3. Match URI pattern (including {id} params)
  4. Run middleware (auth, csrf, etc.)
  5. Inject route params into $_GET
  6. Require the controller file

The controller file runs and generates the response.


Key Takeaways

  1. Bootstrap prepares the framework - Loads config, creates container, binds services
  2. Container manages shared objects - Database, Request, etc.
  3. Routes map URLs to controllers - Simple and explicit
  4. Platform is optional - .dalt can be removed without breaking the core
  5. User routes have priority - Your app routes load first

What's Good Here

✅ Clear separation: core vs platform
✅ Container pattern for dependency injection
✅ Routes are explicit and easy to understand
✅ Request object wraps superglobals cleanly
✅ Lazy loading of database (only created when needed)
✅ Safe .env loading (doesn't crash if file missing)


Next, we'll look at error handling and how validation errors flow through the system.

On this page