Routing

PointArt uses PHP attributes to define routes directly on controller classes and methods — no configuration files, no route registration boilerplate.

Namespaces PointStart\Attributes — Router, Route, HttpMethod, RequestParam
PointStart\Core — App, RouteHandler, Renderer

Request Lifecycle

HTTP Request │ ▼ index.php ← single entry point │ ▼ App::boot() ← creates Container + Router, dispatches │ ├── Container ← resolves Controller + its dependencies │ ├── Router ← matches URL + HTTP method to a Controller method │ ▼ Controller method ← business logic, calls Model statics │ ▼ Renderer::render() ← extracts vars, requires .php view file │ ▼ HTML Response

Controllers

Place controllers in app/components/. They are auto-scanned on the first request. Mark a class with #[Router] and its methods with #[Route].

#[Router(name: 'user', path: '/user')]
class UserController {

    #[Route('/list', HttpMethod::GET)]
    public function index(): string {
        $users = User::findAll();
        return Renderer::render('user.list', ['users' => $users]);
    }

    #[Route('/show/{id}', HttpMethod::GET)]
    public function show(int $id): string {
        $user = User::find($id);
        if ($user === null) {
            return Renderer::render('user.notfound');
        }
        return Renderer::render('user.show', ['user' => $user]);
    }

    #[Route('/create', HttpMethod::POST)]
    public function create(
        #[RequestParam] string $name,
        #[RequestParam] string $email
    ): string {
        $user = new User();
        $user->name  = $name;
        $user->email = $email;
        $user->save();
        return Renderer::render('user.show', ['user' => $user]);
    }
}

#[Router]

ParameterTypeRequiredDescription
pathstringNoURL prefix applied to every route in the class (e.g. '/user'). Default: ''
namestringNoLogical name for the controller. Default: ''

#[Route]

ParameterTypeRequiredDescription
pathstringYesRoute path, relative to the controller prefix. Supports {param} placeholders
methodHttpMethodNoHttpMethod::GET or HttpMethod::POST. Default: GET
csrfExemptboolNoSkip CSRF validation for this route (e.g. webhooks, public APIs). Default: false
CSRF exemption CSRF protection is enabled for all POST routes by default. Set csrfExempt: true to bypass it for a specific route — useful for webhook receivers or public API endpoints that authenticate another way.
#[Route('/webhook', HttpMethod::POST, csrfExempt: true)]
public function webhook(): array { ... }
See Configuration → CSRF for full details.

Method Parameters

The framework injects values into your method parameters from three sources:

SourceHow to DeclareExample
URL path segment Typed parameter matching {name} in the route int $id for /show/{id}
Query string ($_GET) Typed parameter with a default value string $name = '' for ?name=foo
POST body / file upload #[RequestParam] on the parameter #[RequestParam] string $email

Route Pattern Matching

The router first tries an exact match, then falls back to pattern matching for routes with {param} placeholders:

// Registered route: /product/show/{id}
// Request:          /product/show/42
// Result:           $id = 42 → passed to the controller method

#[RequestParam]

No parameters. Tells the framework to inject the value from $_POST or $_FILES for this method parameter. Without it, only path parameters and $_GET values are injected.

Return Types

Return ValueResponse
stringEchoed as HTML
array or objectJSON-encoded with Content-Type: application/json

Next: Dependency Injection →