Installation
composer require 2lenet/dashboard2-bundle
Add routes in config/routes.yaml:
dashboard_widgets:
resource: "@LleDashboardBundle/Resources/config/routes.yaml"
Database Setup
php bin/console make:migration
php bin/console doctrine:migrations:migrate
First Widget Generate a widget using the maker:
php bin/console make:widget
Provide a short name (e.g., user_stats), and the bundle generates a class and template.
Verify Widget Visibility Ensure the widget appears in the dashboard. If not, check:
ROLE_DASHBOARD_<WIDGET_NAME>).php bin/console cache:clear).Widget Creation
Extend AbstractWidget and implement render(), getName(), and optionally supports().
Example:
use Lle\DashboardBundle\Widgets\AbstractWidget;
class UserStatsWidget extends AbstractWidget {
public function render() {
return $this->twig("widget/user_stats.html.twig", [
"users" => $this->getUserService()->getActiveUsers()
]);
}
public function getName() {
return "user_stats.title"; // Translatable
}
}
Templating
Extend @LleDashboard/widget/base_widget.html.twig:
{% extends '@LleDashboard/widget/base_widget.html.twig' %}
{% block widget_content %}
<div>{{ users|length }} active users</div>
{% endblock %}
Dynamic Data Fetching
Use dependency injection (e.g., UserService) in the widget constructor:
public function __construct(private UserService $userService) {}
Configuration Add a form for user-configurable settings:
public function render() {
$form = $this->createForm(UserStatsType::class);
return $this->twig("widget/user_stats.html.twig", [
"config_form" => $form->createView(),
"users" => $this->userService->getUsers($this->getConfig("filter"))
]);
}
Caching
Override getCacheKey() and getCacheTimeout() for performance:
public function getCacheKey() {
return $this->getId() . "_" . md5($this->getConfig("filter"));
}
public function getCacheTimeout() {
return 300; // 5 minutes
}
Static Dashboard
Implement StaticWidgetProviderInterface for fixed layouts:
public function getMyWidgets(): array {
return [
"users" => $this->buildWidget(UserStatsWidget::class, ["title" => "Active Users"])
];
}
ChartJS Integration
Implement ChartProviderInterface for dynamic charts:
public function getChartList(): array {
return ["daily_active_users", "monthly_signups"];
}
public function getChart(string $confKey): Chart {
$data = $this->fetchChartData($confKey);
return $this->chartBuilder->createChart(Chart::TYPE_LINE)
->setData($data)
->setOptions(["responsive" => true]);
}
Role-Based Access
Override supports() to restrict visibility:
public function supports(): bool {
return $this->security->isGranted('ROLE_ADMIN');
}
PDF Export
Customize export settings in render():
return $this->twig("widget/report.html.twig", [
"exportable" => ["orientation" => "landscape", "format" => "a4"]
]);
Widget Not Appearing?
ROLE_DASHBOARD_<WIDGET_NAME>. Ensure users have this role.symfony/ux-chartjs for charts).render().php bin/console cache:clear
php bin/console asset:install
Static Dashboard 404s
config/routes.yaml:
home:
path: /
controller: Lle\DashboardBundle\Controller\StaticDashboardController::staticDashboard
Widget Configuration Not Saving
getConfig() to retrieve values:
$filter = $this->getConfig("filter", "all"); // Default to "all"
ChartJS Not Rendering
symfony/ux-chartjs is installed and the widget implements ChartProviderInterface.Migration Failures
widgets table before running migrate. Example schema:
$table->id();
$table->string('type');
$table->json('config')->nullable();
$table->integer('position');
$table->string('user_id')->nullable();
Log Widget Data
Add debug logs in render() to inspect data:
$this->logger->debug("Widget data:", ["config" => $this->config]);
Override Base Template
To debug rendering issues, override the base template and add {{ dump(widget) }}:
{% extends '@LleDashboard/widget/base_widget.html.twig' %}
{% block widget_content %}
{{ dump(widget) }}
<!-- Your content -->
{% endblock %}
Disable Cache Temporarily
Set getCacheTimeout() to 0 to bypass caching during development:
public function getCacheTimeout() { return 0; }
Custom Widget Types
Create a custom maker command by extending make:widget:
php bin/console make:command CustomWidgetMaker
Override configure() to generate specialized widgets.
Dynamic Widget Loading Use Symfony’s autowiring to lazy-load widgets:
public function __construct(private iterable $widgetTypes) {}
Filter widgets by interface or trait (e.g., ChartProviderInterface).
Widget Events Dispatch events for cross-cutting concerns (e.g., logging, analytics):
$this->eventDispatcher->dispatch(new WidgetRenderEvent($this));
Static Dashboard Extensions
Add a refresh button by extending the static dashboard template:
<button onclick="refreshStaticDashboard('{index}')">Refresh</button>
Implement AJAX endpoint in StaticDashboardController.
Widget Testing
Test widgets in isolation using WidgetTestCase:
use Lle\DashboardBundle\Tests\WidgetTestCase;
class UserStatsWidgetTest extends WidgetTestCase {
public function testRender() {
$widget = new UserStatsWidget($this->security);
$html = $widget->render();
$this->assertStringContainsString("Active Users", $html);
}
}
How can I help you explore Laravel packages today?