mch0lic/open-flash-chart-bundle
Symfony bundle integrating Open Flash Chart, providing PHP object wrappers, Twig helpers, and controller integration so you can build and render flash-based charts from application data with minimal configuration and reusable chart definitions.
First, a reality check on fit. This repository is a Symfony2 bundle, not a Laravel package. There is no ServiceProvider, no config/open-flash-chart.php, and no facade. You will not composer require it into a Laravel app and get a working integration. What you actually want from it is the OFC2 PHP class library that the bundle wraps — the code that builds chart objects and serializes them to the JSON that open-flash-chart.swf consumes. That class library is framework-agnostic and drops into Laravel cleanly.
Minimal steps in a Laravel app:
mch0lic/open-flash-chart library (the core of this bundle) via Composer, or copy the OFC//lib/ directory out of the bundle into app/Support/OpenFlashChart/ and register it with a classmap or PSR-4 entry in composer.json.open-flash-chart.swf (and the js/swfobject.js if you follow the original docs) in public/vendor/ofc/.Where to look first: open the bundle's Controller/ and Resources/views/ — that's the canonical example of "build chart object → toPrettyString() → return application/json". Then read the class list in the bundled OFC library to see the element types (Chart, Chart\Line, Chart\Bar, Chart\Axis, Chart\Pie, Chart\Tooltip, etc. — exact namespacing depends on the fork you vendor).
First use case — the canonical one:
// routes/web.php
Route::get('/reports/monthly.json', [ReportChartController::class, 'monthly'])->name('chart.monthly');
// ReportChartController
public function monthly()
{
$chart = new \OFC\Chart();
$chart->set_title(new \OFC\Chart\Title('Monthly Signups'));
$bar = new \OFC\Chart\Bar();
$bar->set_values(Order::whereYear('created_at', now()->year)->pluck('count')->all());
$chart->add_element($bar);
return response($chart->toPrettyString())
->header('Content-Type', 'application/json');
}
{{-- resources/views/reports/index.blade.php --}}
<div id="chart-monthly" style="width:600px;height:400px"></div>
<script src="{{ asset('vendor/ofc/swfobject.js') }}"></script>
<script>
swfobject.embedSWF(
"{{ asset('vendor/ofc/open-flash-chart.swf') }}",
"chart-monthly",
"600", "400", "9.0.0",
"expressInstall.swf",
{ "data-file": "{{ route('chart.monthly') }}" }
);
</script>
If that swfobject block makes you uneasy in 2025 — it should. See Gotchas.
Separate the JSON endpoint from the view. This is the single most important structural decision. Never render the SWF inline in the same action that builds the data. A dedicated JSON route lets you:
Cache::remember('chart.monthly.'.now()->format('Y-m'), 3600, fn () => $chart->toPrettyString()))Put chart builders in their own classes. The bundle's fluent API is perfectly suited to a small app/Charts/ namespace:
namespace App\Charts;
class SignupsChart
{
public function __construct(private array $values) {}
public function build(): \OFC\Chart
{
$chart = new \OFC\Chart();
$chart->set_bg_colour('#f9f9f9');
$chart->set_title(new \OFC\Chart\Title('Signups'));
$line = new \OFC\Chart\Line();
$line->set_values($this->values);
$line->set_colour('#3366cc');
$line->set_width(2);
$x = new \OFC\X_Axis();
$x->set_labels(['Jan','Feb','Mar','Apr','May','Jun']);
$chart->set_x_axis($x);
$chart->add_element($line);
return $chart;
}
public function json(): string
{
return $this->build()->toPrettyString();
}
}
Typical data flow from Eloquent:
$rows = Order::where('created_at', '>=', now()->subYear())
->selectRaw("DATE_FORMAT(created_at,'%Y-%m') as ym, COUNT(*) as total")
->groupBy('ym')->orderBy('ym')->pluck('total', 'ym');
(new SignupsChart($rows->values()->all()))->json();
Dashboard composition. The original OFC2 usage pattern is one SWF per chart. On a dashboard you end up with N embeds and N JSON routes — that's fine, but lazy-load them (only embed when the tab is visible) so you don't fire 8 Flash instantiations on page load.
Caching and pre-computation. Since the SWF is doing the rendering, the PHP side is cheap. Cache the JSON string, not the PHP object — the object graph contains closures/state that serialize poorly.
Testing pattern. Your chart code is testable without any Flash at all. Assert the JSON decodes and contains the shape you expect:
$json = json_decode((new SignupsChart([1,2,3]))->json(), true);
$this->assertSame([1,2,3], $json['elements'][0]['values']);
This is where a lot of real value hides — you get regression protection on the data mapping even though the visual output is untestable.
Flash is dead. This is the elephant. Adobe ended Flash support on 31 December 2020 and browsers blocked it in January 2021. open-flash-chart.swf will not run in any current mainstream browser. Your only paths are: (a) run it in a legacy locked-down intranet browser, (b) run it through Ruffle (https://ruffle.rs), a WASM Flash emulator — which works for simple OFC2 SWFs but is not guaranteed to support every feature, or (c) do not use this package at all and treat the assessment as a code-to-port exercise. If this is a greenfield project, use Chart.js, ApexCharts, ECharts, or a server-side renderer like QuickChart. Keep this package in mind only for maintaining an existing Flash-era app.
No Laravel integration exists. No service provider, no facade, no package config. You must wire autoloading manually. If the library's namespaces don't match PSR-4 (older forks use OFC_-prefixed global classes), add a classmap block to composer.json and composer dump-autoload.
Two different API generations. The bundle was written against a PHP 5.3+ namespaced fork. Older tutorials and StackOverflow answers use the original global-class API (open_flash_chart, chart_line, chart_bar, x_axis). Mixing the two produces confusing "class not found" / "method does not exist" errors. Pick one API generation based on the code you actually vendored and stick to it.
JSON encoding quirks. toPrettyString() is for debugging and produces indented output; toString() is the compact form the SWF actually prefers. For large datasets, pretty-printed JSON bloats responses meaningfully. Also watch colors: OFC2 expects #RRGGBB strings, and a missing # silently produces a black element with no error.
Numeric axis scaling is manual. OFC2 does not auto-choose nice axis bounds the way modern charting libs do. If your data spikes, your bars go off the top. Set y_axis->set_range(min, max, step) explicitly based on your data's max — otherwise you'll file bugs against your own mapping code.
Debugging strategy. When a chart renders blank or wrong, the problem is almost always the JSON, not the SWF. Hit the JSON route directly in a browser, copy the response, and validate it against the OFC2 schema tester (the OFC2 distribution ships an ofc2_test.html page — you can often dig one out of the upstream repo). json_decode the string in tinker and eyeball the structure. If the JSON is valid but the chart still won't render, it's a Flash/plugin issue, not your code.
Escape hatch / migration path. Because the chart builders are just "data in → JSON string out", these classes are a clean seam to swap out later. Keep the App\Charts\* contract returning a plain array or a chart-agnostic intermediate, and add a second toChartJs() method. You can then migrate pages off Flash incrementally without rewriting the data queries — this is the single best reason to keep the chart construction in dedicated classes rather than inline in controllers.
Extension points worth knowing. Tooltip, X_Axis label rotation (set_labels(..., $rotate)) and set_colours() on pie/bar elements are the knobs people reach for most. If you need something the library doesn't expose, subclass the element and override the to_array() / serialization method — the library serializes via plain array building, so it's tractable.
Security note. Never reflect raw user input into a chart title or tooltip template without escaping — OFC2 tooltips support HTML-ish templates, and the SWF will happily render whatever markup it's given. Treat chart JSON as untrusted output.
How can I help you explore Laravel packages today?