nette/application
Nette Application is the web framework core of the Nette stack, providing MVC architecture with presenters, routing, DI integration, HTTP handling, and error/debug support. Build secure, structured PHP web apps with clean separation of concerns.
Installation
composer require nette/application nette/routing nette/di
Note: Laravel’s built-in DI container won’t work directly; use Nette\DI\Container or bridge it via Laravel’s ServiceProvider.
Front Controller (public/index.php)
require __DIR__.'/../vendor/autoload.php';
$container = new Nette\DI\Container();
$router = new Nette\Application\Routers\RouteList();
$router[] = $router->addRoute('<presenter>/<action>', 'Homepage:default');
$application = new Nette\Application\Application(
$container,
$router,
new Nette\Application\UI\PresenterFactory()
);
$application->run();
First Presenter (app/Presenters/HomepagePresenter.php)
namespace App\Presenters;
use Nette\Application\UI\Presenter;
class HomepagePresenter extends Presenter {
public function renderDefault() {
$this->template->message = 'Hello, Laravel + Nette!';
}
}
Template (app/Presenters/templates/Homepage/default.latte)
{layout @layout}
<h1>{$message}</h1>
Laravel Route Proxy (Optional)
In routes/web.php, proxy requests to Nette’s front controller:
Route::get('/{path?}', function ($path = '') {
return app('nette.application')->run();
})->where('path', '.*');
Presenter:action → maps to Presenter.php and Presenter/templates/action.latte.$router[] = $router->addRoute(
'<presenter>/<action>/<id>',
'Homepage:show',
['id' => '[0-9]+']
);
// In Presenter
public function handleSubmit() {
$this->getComponent('form')->onSuccess[] = [$this, 'formSucceeded'];
}
public function formSucceeded($form) {
$this->flashMessage('Success!');
}
// Nette DI (app/presenters.di.php)
$container->addService('database', new Nette\Database\Connection($dsn));
// In Presenter
public function __construct(Nette\Database\Connection $db) {
$this->db = $db;
}
Nette\DI\Container as a Laravel service provider:
class NetteServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton('nette.application', function () {
return new Nette\Application\Application(
new Nette\DI\Container(),
new Nette\Application\Routers\RouteList(),
new Nette\Application\UI\PresenterFactory()
);
});
}
}
{extends @layout}
{block content}
<p>Dynamic content via {template variables}.</p>
{/block}
{control user/avatar}
$form = new Nette\Application\UI\Form;
$form->addText('name', 'Name:');
$form->onSuccess[] = [$this, 'processForm'];
// In template
{control form}
$application->setErrorPresenter('Error4xxPresenter');
$this->flashMessage('Error!', 'warning');
// In template: {flashMessages}
DI Container Conflict:
Container is not Laravel’s Container. Use a facade or bridge:
$netteContainer = new Nette\DI\Container();
$this->app->instance('nette.container', $netteContainer);
Nette\DI\Container for Nette-specific services and Laravel’s container for Laravel services.Route Overlap:
RouteList both process requests. Use middleware to delegate:
Route::get('/nette/{path}', function ($path) {
return app('nette.application')->run();
})->middleware('nette');
Template Naming:
Presenter/templates/ActionName.latte. Laravel’s views/ won’t work directly.Presenter::setTemplateDirectory().Signal vs. Event:
onSignal[] is not Laravel’s Event::dispatch(). Use a bridge:
// Convert Nette signal to Laravel event
$this->onSignal[] = function ($signal) {
event(new NetteSignalEvent($signal));
};
Persistent Parameters:
@Persistent (e.g., #[Persistent] public int $page = 1) persists across requests.session() or cookie().Tracy Integration:
index.php:
if (APP_DEBUG) {
$application->getService('debugger')->enable();
}
tracy/tracy for Laravel debugging alongside Nette.Common Errors:
InvalidLinkException: Check Presenter::link() arguments (e.g., Homepage:default vs. Homepage).BadRequestException: Validate Presenter::handle* methods for non-void returns.ApplicationExtension:
$extension->templateCache = __DIR__.'/../temp/cache/latte';
PresenterFactoryCallback for lazy-loading presenters:
$factory = new Nette\Application\UI\PresenterFactory();
$factory->setCallback('Homepage', [$this, 'createHomepage']);
class ApiPresenter extends Presenter {
public function renderJson(array $data) {
http_response_code(200);
header('Content-Type: application/json');
echo json_encode($data);
}
}
$application->addMiddleware(function ($request, $next) {
// Modify request before Nette processes it
return $next($request);
});
| Laravel Concept | Nette Equivalent | Migration Tip |
|---|---|---|
| Route controllers | Presenters (Presenter:action) |
Move logic from Route::get() to Presenter::render*(). |
| Blade templates | Latte templates | Use {extends @layout} for shared layouts. |
| Service Container | Nette DI ($container->addService()) |
Prefer constructor injection over app()->make(). |
| Events | Signals ($component->onSignal[]) |
Use a facade to dispatch Laravel events. |
| Middleware | Application::addMiddleware() |
Wrap Laravel middleware in a Nette callable. |
| Validation | Nette Forms ($form->addRule()) |
Replace Validator with Nette\Forms\Container. |
| CSRF Protection | Built into Presenter |
No extra config needed. |
How can I help you explore Laravel packages today?