gremo/highcharts-bundle
HighchartsBundle integrates Highcharts into Symfony applications, letting you build interactive JavaScript charts from PHP with a fluent, chainable API and Twig helpers. Configure options server-side without writing JavaScript.
First, calibrate expectations: this is a Symfony2 bundle, not a Laravel package. There is no service provider, no facade, no config/highcharts.php. It was archived in 2013, targets PHP 5.3–5.4 and Symfony 2.x, and pins a Highcharts 2.x/3.x-era JavaScript API. If you are on Laravel 8+, you cannot install it meaningfully — Composer will fight you on symfony/framework-bundle constraints. The realistic "getting started" is either (a) reading it as a reference implementation to port, or (b) using it in a legacy Symfony app you inherited.
For the legacy case:
composer require gremo/highcharts-bundle (expect to relax minimum-stability and possibly patch constraints).new Gremo\HighchartsBundle\GremoHighchartsBundle() in AppKernel.php. No bundle config is required.gremo_highcharts) from the container, build a chart in a controller, hand it to Twig, and call the render helper.Minimal first use case:
$chart = $this->get('gremo_highcharts')->newChart()
->setTitle(['text' => 'Signups'])
->setXAxis(['categories' => ['Mon', 'Tue', 'Wed']])
->addSeries(['name' => 'Web', 'data' => [3, 7, 4]]);
return $this->render('report.html.twig', ['chart' => $chart]);
{{ highcharts_render(chart) }}
Where to look first: the Highcharts factory class (its __call magic defines the entire fluent surface), the Twig extension (the highcharts_render / asset helpers), and the bundle's tests — the tests are the only reliable documentation of which option keys are normalized versus passed through verbatim.
Build charts in a service, not a controller. The fluent object is a plain PHP options container; it serializes to a JS object literal at render time. Put chart construction in a ChartBuilder-style service so the controller stays thin and the chart becomes testable ($chart->getOptions() is just an array).
Lean on the magic setter, but map it deliberately. setTitle(), setXAxis(), addSeries(), setTooltip() map to Highcharts option keys (title, xAxis, series, tooltip). Because it's __call-based, the convention is "set + StudlyCase option name". Create a thin wrapper with explicit methods for the five or six charts your app actually renders, so typos surface at code review instead of producing a silently empty chart.
One partial per chart type. Keep _chart_line.html.twig, _chart_pie.html.twig, etc., each calling highcharts_render. This is the closest thing the bundle has to a component model and it keeps the JS emission in one place per chart family.
For dynamic data, invert the pattern. The bundle is server-render-first. For dashboards that filter/refresh, expose a JSON endpoint returning $chart->getOptions() and instantiate Highcharts client-side with Highcharts.chart('container', options). You keep the fluent builder as your options factory and drop the render helper entirely — this is also the cleanest port path off the bundle.
Asset handling. Use the bundle's script/asset helper in your base layout to emit the Highcharts <script> tag, then highcharts_render in the body. Don't hardcode a CDN URL in two places; the helper is the intended seam for swapping versions.
Integration tip for Laravel devs porting the idea: the pattern that survives is "server builds an options array, template/JSON hands it to the JS lib." A Laravel equivalent is a Chart value object with toArray() plus a Blade partial that does Highcharts.chart(el, @json($chart->toArray())). Maintained alternatives (Larapex Charts, ConsoleTVs/Charts, or just hand-rolled ApexCharts/ECharts options) give you the same shape without the abandoned dependency.
__call fails silently. An unknown setFoo() throws, but a known method with a misnamed option key inside the array passes straight through to Highcharts, which ignores it. Validate against the Highcharts option docs, and write one smoke test per chart asserting key option paths exist.formatter, pointFormatter, axis label.formatter, and event handlers are functions. The bundle serializes PHP arrays to JSON, so functions get dropped or stringified. You need a raw-JS escape hatch (a raw/JsExpression-style value, or post-process the emitted literal) — check the extension for how it handles this before assuming it works.DECIMAL columns via PDO) serialize as "12.5", and Highcharts may render them as categories or skip them. Cast to (float) in the builder.xAxis/yAxis shape drift. Highcharts accepts an object or an array of axis configs. The bundle's fluent helpers assume one shape; mixing them produces a chart that renders axes in the wrong place. Stick to one convention per project.highcharts_render emits an inline <script>. Under a strict Content-Security-Policy you need a nonce or hash, or you must switch to the JSON-endpoint pattern. Also confirm the helper marks its output safe in Twig; if not, you'll see escaped JS as visible text.Highcharts factory to add your own defaults (colors, credits, exporting); (2) override the Twig extension service to change how scripts are emitted; (3) avoid forking the bundle — it will never receive upstream fixes.chart.renderTo handling, module loading, Highcharts.chart vs new Highcharts.Chart). Lock the JS version in your asset pipeline rather than floating a CDN latest, or a CDN bump will break every chart at once.getOptions(). Snapshot that array from a running legacy app, diff it against your target library's schema, and port chart-by-chart — that's a mechanical, testable migration rather than a rewrite.How can I help you explore Laravel packages today?