Weave 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

Widget Bundle Laravel Package

toro/widget-bundle

toro/widget-bundle provides a flexible widget system for PHP applications. Define reusable widget types, assign them to configurable areas, and render them in templates with caching and straightforward configuration for CMS-style content blocks.

View on GitHub
Deep Wiki
Context7

Getting Started

Read the environment before the code. This is a Symfony2 bundle, not a Laravel package. It ships no ServiceProvider, no config/ publish tag, no Facade, and it pre-dates Composer auto-discovery. composer require toro/widget-bundle will succeed, but nothing in a Laravel app will register or boot it. The last release was July 2017 against the Symfony 2.x/3.x line, so treat it as a reference implementation rather than a dependency.

First places to look, in order:

  1. composer.json — the symfony/symfony (or symfony/framework-bundle) constraint and required PHP version tell you immediately whether it can even resolve on your stack.
  2. ToroWidgetBundle.php — bundles of this kind do their real work in build() via compiler passes; that's where widget types get registered into a registry.
  3. DependencyInjection/Configuration.php — the config tree (likely a toro_widget: root) defines every knob you can tune.
  4. Resources/config/*.yml — the service wiring, the tag name used for widget discovery, and any Twig extension registration.
  5. Resources/views/ — the Twig templates that actually render widgets.

First use case, honestly stated: the only environment where this runs as designed is a throwaway Symfony 2.8/3.x app on PHP 5.6–7.1. Register the bundle in AppKernel, add the config block, and render a widget in a Twig template. If you can't reproduce that in 30 minutes, stop — you've confirmed the maintenance cost is higher than reimplementing the pattern.

For the Laravel codebase you actually ship: do not install it. Read it as a spec for a widget/block system and port the concept to Blade + the service container (see below). If you are genuinely forced into a hybrid (legacy Symfony service you must consume), expose widget rendering behind an HTTP endpoint and call it from Laravel — never try to boot Symfony's DI inside Laravel.

Implementation Patterns

The bundle's design is the standard Symfony recipe for a pluggable widget system. Each piece has a direct Laravel equivalent, and mapping them is the fastest way to port.

1. Widget registry instead of a compiler pass. Symfony discovers widgets by service tag; a compiler pass collects them into a registry. In Laravel, bind a singleton and register explicitly during boot:

// app/Providers/WidgetServiceProvider.php
public function register(): void
{
    $this->app->singleton(WidgetRegistry::class, fn () => new WidgetRegistry());
}

public function boot(): void
{
    $registry = $this->app->make(WidgetRegistry::class);

    $registry->register('latest-posts', LatestPostsWidget::class);
    $registry->register('promo-banner', PromoBannerWidget::class);
}

2. A widget contract mirroring the bundle's base class. The Symfony side almost certainly exposes a render(array $options): string style method. Keep that shape so the port stays a mechanical translation:

interface Widget
{
    public function render(array $options = []): View;
}

class LatestPostsWidget implements Widget
{
    public function __construct(private PostRepository $posts) {}

    public function render(array $options = []): View
    {
        return view('widgets.latest-posts', [
            'posts' => $this->posts->latest($options['limit'] ?? 5),
        ]);
    }
}

3. Rendering surface: Twig function → Blade component or helper. The bundle wires a Twig function (likely {{ toro_widget('name', {...}) }}). The Laravel equivalent is a Blade component or a small helper:

// app/Support/helpers.php
function widget(string $name, array $options = []): Htmlable
{
    return app(WidgetRegistry::class)->render($name, $options);
}
{{-- resources/views/widgets/slot.blade.php --}}
{!! widget($name, $options ?? []) !!}

A Blade component (<x-widget name="latest-posts" :limit="5" />) is the cleaner fit if you want prop validation and attribute bagging.

4. Configuration: YAML tree → published config file. Port Configuration.php into config/widgets.php, publish it with php artisan vendor:publish, and read it via config('widgets.*'). Keep the same nesting so operators migrating from the Symfony app recognize the keys.

5. Integration tips.

  • Keep widget rendering stateless and cache-friendly; wrap expensive widgets in Cache::remember keyed by widget name + options hash.
  • If widgets appear in CMS-managed pages, store the widget name + JSON options in the page record and resolve at render time — this replaces the bundle's config-driven placement.
  • Use view composers only for global chrome (nav, footer); per-page widgets should go through the registry so they stay testable in isolation.
  • Write one feature test per widget ($this->get('/')->assertSee(...)) — the ported system has no upstream test coverage to lean on.

Gotchas and Tips

  • It is not a Laravel package. Zero stars and zero dependents confirm there is no Laravel adapter, no auto-discovery, and no community to answer questions. Any integration work is yours alone.
  • Composer will fight you. The 2017 constraints will conflict with modern symfony/* packages and often with PHP 8. Resist --ignore-platform-reqs; you'll get runtime fatals from removed Symfony APIs (notably the Symfony 4 DI rewrite) rather than a clean failure.
  • Twig templates are not reusable. Plan to rewrite every view in Blade; the markup is the only thing you can copy.
  • No maintenance and no CVE history. Treat the source as unaudited. If you vendor any of it, pin the commit and note it in your dependency review.
  • Debugging uses Symfony tooling, not Laravel's. In the throwaway Symfony app, bin/console debug:container --tag=<widget_tag> and debug:event-dispatcher tell you whether a widget registered; Laravel's php artisan about and container dumps are useless for the bundle itself.
  • The real extension point is the service tag / compiler pass. If you're porting, replicate the tag-collection semantics in your registry (register() + iteration order) so widget precedence and overriding behave the same way.
  • Config tree strictness. Symfony's Configuration.php will throw on unknown keys; Laravel's config arrays silently ignore typos. Add validation in your provider or a config test, or you'll ship a config that looks applied but isn't.
  • Don't put widget state in the container. The bundle's widgets are services and therefore singletons per request; if you cache per-widget data on the instance, you'll leak state between renders. Keep the ported widgets stateless and pass everything through $options.
  • Migration exit criterion: if after reading ToroWidgetBundle.php and the config tree you find the feature set is "render named partial with options," port it in an afternoon. That is very likely the whole package.
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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core