Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Component Model Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup for Laravel Integration

  1. Install the Package

    composer require nette/component-model
    

    Note: No Laravel-specific service provider or Facade exists—manual integration required.

  2. 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).

  3. 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\ContainerIlluminate\Container.

  4. 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.


Implementation Patterns

Core Workflows

1. Component Hierarchy Management

  • Pattern: Use Container to manage parent-child relationships.
    $parent = new Container();
    $child = new ChildComponent($parent, 'child-name');
    $parent->addComponent($child);
    
  • Laravel Integration Tip: Wrap Nette\Container in a Laravel ServiceProvider to bind it as a singleton:
    $this->app->singleton('nette.container', function () {
        return new Container();
    });
    

2. Lifecycle Events with monitor()

  • Pattern: Attach callbacks to component attachment/detachment.
    $component->monitor(Component::ATTACHED, function ($component) {
        // Runs when component is added to a container
        Log::info("Component {$component->getName()} attached.");
    });
    
  • Laravel Equivalent: Replace with Laravel’s Events system if possible:
    event(new ComponentAttached($component));
    

3. Component Lookup

  • Pattern: Retrieve components by name/path.
    $dashboard = $container->getComponent('dashboard');
    $profile = $dashboard->getComponent('profile'); // Nested lookup
    
  • Advanced: Use getComponentTree() for debugging:
    $tree = $container->getComponentTree();
    // Outputs hierarchical structure (e.g., for admin panels)
    

4. ArrayAccess for Dynamic Components

  • Pattern: Use ArrayAccess trait for dynamic component access.
    $container['dynamic-component'] = new DynamicComponent($container);
    $component = $container['dynamic-component'];
    

Integration Tips

Bridging with Laravel’s Service Container

  • Manual Binding: Register Nette\Container as a Laravel service:
    $this->app->bind('nette.container', function () {
        return new Container();
    });
    
  • Component Resolution: Create a custom resolver for Component instances:
    $this->app->resolving(Component::class, function ($component, $app) {
        $app['nette.container']->addComponent($component, $component->getName());
    });
    

Blade Integration (Experimental)

  • Custom Blade Directive: Extend Blade to render Component instances.
    Blade::directive('component', function ($name) {
        return "<?php echo app('nette.container')->getComponent({$name})->render(); ?>";
    });
    
  • Use Case: Render hierarchical components in Blade templates (e.g., nested modals).

Livewire Hybrid Approach

  • Extend Livewire Components with 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
    }
    
  • Tradeoff: Adds complexity but enables monitor() for Livewire components.

Gotchas and Tips

Pitfalls

1. No Laravel-Specific Features

  • Issue: Missing Facades, service binding helpers, or Laravel event integration.
  • Fix: Manually bridge Nette\ContainerIlluminate\Container (see Implementation Patterns).

2. Deprecated Magic Properties (v3.2+)

  • Issue: Component::$name, Container::$components are deprecated. Use getters:
    // Wrong (deprecated):
    $name = $component->name;
    
    // Correct:
    $name = $component->getName();
    
  • Tip: Run phpstan with nette/phpstan-rules to catch deprecations early.

3. Reentry Protection in monitor()

  • Issue: Nested monitor() callbacks may cause infinite loops. Use refreshMonitors() carefully:
    $component->monitor(Component::ATTACHED, function ($comp) {
        if ($comp->getName() === 'critical') {
            $comp->getParent()->refreshMonitors(); // Risky!
        }
    });
    
  • Fix: Avoid recursive refreshMonitors() calls. Use Laravel’s Events instead.

4. PHP 8.1+ Strict Typing

  • Issue: Requires declare(strict_types=1) and PHP 8.1+. Older Laravel apps may need upgrades.
  • Tip: Use returnTypeWillChange in phpstan.neon for transitional code:
    parameters:
        returnTypeWillChange: Component::class
    

5. Component Naming Conflicts

  • Issue: Laravel’s Component (Blade/Livewire) vs. Nette\ComponentModel\Component.
  • Fix: Use fully qualified namespaces or aliases:
    use Nette\ComponentModel\Component as NetteComponent;
    

Debugging Tips

1. Inspect Component Tree

$tree = $container->getComponentTree();
dump($tree); // Hierarchical array for debugging
  • Laravel Integration: Log the tree to telescope:
    \Illuminate\Support\Facades\Log::debug('Component Tree', ['tree' => $tree]);
    

2. Monitor Callback Debugging

  • Enable Reentry Protection:
    $component->monitor(Component::ATTACHED, function ($comp) {
        if (debug_backtrace(false)) {
            Log::debug('Monitor callback triggered for ' . $comp->getName());
        }
    });
    
  • Check for Duplicates: Use loose comparison for callbacks (v3.1.4+):
    $component->monitor(Component::DETACHED, $callback);
    // Deduplication is now reliable
    

3. Static Analysis

  • Run PHPStan:
    vendor/bin/phpstan analyse --level 8 src
    
  • Focus on:
    • Nette\ComponentModel\IComponent violations.
    • Deprecated magic properties (v3.2+).

Extension Points

1. Custom Container Adapter

  • Extend 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);
        }
    }
    

2. Event-Driven Lifecycle

  • Bridge monitor() to Laravel Events:
    $component->monitor(Component::ATTACHED, function ($comp) {
        event(new \App\Events\ComponentAttached($comp));
    });
    

3. Blade Component Wrapper

  • Create a NetteComponent Blade directive:
    Blade::if('netteComponent', function ($name) {
        return app('nette.container')->getComponent($name);
    });
    
    Usage:
    @netteComponent('dashboard')
    

4. Type-Safe Components (PHP 8.5+)

  • Leverage typed properties in Component subclasses:
    class UserProfileComponent extends Component
    {
        public function __construct(
            private string $userId,
            private ?User $user = null,
        ) {
            parent::__construct($parent, 'profile');
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle