nette/component-model
Nette Component Model provides a lightweight component hierarchy for PHP apps. It supports parent/child relationships, naming, lookup, and lifecycle hooks, making it easy to build reusable UI or service components that can be composed, traversed, and managed consistently.
Install the Package
composer require nette/component-model
Note: No Laravel-specific service provider or Facade exists—manual integration required.
Basic Component Class
use Nette\ComponentModel\Component;
class UserProfileComponent extends Component
{
public function render(): void
{
echo $this->template->render();
}
}
Extend Component instead of Laravel’s Component (Blade/Livewire).
Register in a Container
use Nette\ComponentModel\Container;
$container = new Container();
$container->addComponent(new UserProfileComponent($container, 'user-profile'));
No Laravel service binding by default—use a custom ServiceProvider to bridge Nette\Container ↔ Illuminate\Container.
First Use Case: Hierarchical Components
$dashboard = new Container();
$dashboard->addComponent(new UserProfileComponent($dashboard, 'profile'));
// Access child component by name
$profile = $dashboard->getComponent('profile');
Useful for nested UIs (e.g., modals within panels) where parent-child relationships are explicit.
Container to manage parent-child relationships.
$parent = new Container();
$child = new ChildComponent($parent, 'child-name');
$parent->addComponent($child);
Nette\Container in a Laravel ServiceProvider to bind it as a singleton:
$this->app->singleton('nette.container', function () {
return new Container();
});
monitor()$component->monitor(Component::ATTACHED, function ($component) {
// Runs when component is added to a container
Log::info("Component {$component->getName()} attached.");
});
Events system if possible:
event(new ComponentAttached($component));
$dashboard = $container->getComponent('dashboard');
$profile = $dashboard->getComponent('profile'); // Nested lookup
getComponentTree() for debugging:
$tree = $container->getComponentTree();
// Outputs hierarchical structure (e.g., for admin panels)
ArrayAccess trait for dynamic component access.
$container['dynamic-component'] = new DynamicComponent($container);
$component = $container['dynamic-component'];
Nette\Container as a Laravel service:
$this->app->bind('nette.container', function () {
return new Container();
});
Component instances:
$this->app->resolving(Component::class, function ($component, $app) {
$app['nette.container']->addComponent($component, $component->getName());
});
Component instances.
Blade::directive('component', function ($name) {
return "<?php echo app('nette.container')->getComponent({$name})->render(); ?>";
});
Component:
use Livewire\Component as LivewireComponent;
use Nette\ComponentModel\Component;
class HybridComponent extends LivewireComponent implements Component
{
use \Nette\ComponentModel\IComponent;
public function getName(): string { /* ... */ }
public function getParent(): ?Component { /* ... */ }
// Implement other IComponent methods
}
monitor() for Livewire components.Nette\Container ↔ Illuminate\Container (see Implementation Patterns).Component::$name, Container::$components are deprecated. Use getters:
// Wrong (deprecated):
$name = $component->name;
// Correct:
$name = $component->getName();
phpstan with nette/phpstan-rules to catch deprecations early.monitor()monitor() callbacks may cause infinite loops. Use refreshMonitors() carefully:
$component->monitor(Component::ATTACHED, function ($comp) {
if ($comp->getName() === 'critical') {
$comp->getParent()->refreshMonitors(); // Risky!
}
});
refreshMonitors() calls. Use Laravel’s Events instead.declare(strict_types=1) and PHP 8.1+. Older Laravel apps may need upgrades.returnTypeWillChange in phpstan.neon for transitional code:
parameters:
returnTypeWillChange: Component::class
Component (Blade/Livewire) vs. Nette\ComponentModel\Component.use Nette\ComponentModel\Component as NetteComponent;
$tree = $container->getComponentTree();
dump($tree); // Hierarchical array for debugging
telescope:
\Illuminate\Support\Facades\Log::debug('Component Tree', ['tree' => $tree]);
$component->monitor(Component::ATTACHED, function ($comp) {
if (debug_backtrace(false)) {
Log::debug('Monitor callback triggered for ' . $comp->getName());
}
});
loose comparison for callbacks (v3.1.4+):
$component->monitor(Component::DETACHED, $callback);
// Deduplication is now reliable
vendor/bin/phpstan analyse --level 8 src
Nette\ComponentModel\IComponent violations.Container to integrate with Laravel’s service container:
class LaravelContainer extends Container
{
public function __construct(private $laravelContainer)
{
}
public function getComponent(string $name): Component
{
return $this->laravelContainer->make($name);
}
}
monitor() to Laravel Events:
$component->monitor(Component::ATTACHED, function ($comp) {
event(new \App\Events\ComponentAttached($comp));
});
NetteComponent Blade directive:
Blade::if('netteComponent', function ($name) {
return app('nette.container')->getComponent($name);
});
Usage:
@netteComponent('dashboard')
Component subclasses:
class UserProfileComponent extends Component
{
public function __construct(
private string $userId,
private ?User $user = null,
) {
parent::__construct($parent, 'profile');
}
}
How can I help you explore Laravel packages today?