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

Flatten Laravel Package

anahkiasen/flatten

Flatten is a lightweight PHP/Laravel utility for converting nested arrays and objects into flat, dot-notated arrays and back again. It simplifies working with deeply nested configuration, JSON payloads, and form data by making values easier to access, compare, search, and transform.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer (the package targets Laravel 4-era projects, so expect to pin dependencies):

composer require anahkiasen/flatten

Laravel 4 setup — register the service provider in app/config/app.php:

'providers' => [
    // ...
    'Flatten\FlattenServiceProvider',
],

'aliases' => [
    // ...
    'Flatten' => 'Flatten\Facades\Flatten',
],

Framework-agnostic usage — instantiate the class directly:

use Flatten\Flatten;

$flatten = new Flatten();
$html = $flatten->flatten('https://example.com');
file_put_contents('snapshot.html', $html);

Where to look first

  1. README.md — the canonical API is tiny (flatten($url)), so the README is the whole manual.
  2. src/Flatten/Flatten.php — the flatten() method and its protected helpers (fetch, CSS inlining, URL rewriting) are the only real surface area.
  3. src/Flatten/FlattenServiceProvider.php — confirms whether a config file or singleton binding is registered.
  4. tests/ — best source of truth for edge cases (relative links, <base> tags, CSS @import).

First use case — turn a remote page into a self-contained-ish HTML document for archival, an HTML email template, or a wkhtmltopdf input where styles must be inline rather than in external stylesheets:

$html = Flatten::flatten('https://example.com/pricing');
Storage::put('snapshots/pricing-' . date('Ymd') . '.html', $html);

Implementation Patterns

Cache the output, not the fetch. Flattening a page involves an HTTP fetch plus DOM/CSS parsing. Wrap calls in a repository class and cache by URL + a last-modified fingerprint:

class PageSnapshot
{
    public function get(string $url): string
    {
        return Cache::remember('flatten:' . md5($url), 3600, function () use ($url) {
            return app('flatten')->flatten($url);
        });
    }
}

Queue it for archival/scheduled jobs. Flattening is I/O bound and slow on content-heavy pages. Dispatch a job per URL, write the result to disk/S3, store metadata in a DB row. This is also where you add retries for 5xx/timeout failures.

Post-process the flattened HTML. The package returns a full document; most workflows need to trim it. Combine with symfony/dom-crawler (already a transitive dependency) to strip scripts, iframes, and tracking pixels:

$crawler = new Crawler($html);
$crawler->filter('script, iframe, noscript')->each(fn ($node) => $node->getNode(0)->parentNode->removeChild($node->getNode(0)));
$clean = $crawler->html();

Email template pipeline. Flatten a marketing page, then feed the result into an email inliner (e.g. tijsverkoyen/css-to-inline-styles) if the output keeps <style> blocks rather than attributes. This is a common reason people reach for this package: get a single HTML blob without external CSS links.

Content extraction / readability. Flatten first (so relative links and styles resolve), then run a readability or Markdown converter. Useful for building "reader mode" views or feeding an LLM ingest pipeline where you want clean HTML rather than a CSS-dependent page.

PDF generation preprocessing. If you render HTML to PDF with wkhtmltopdf or Dompdf, flatten the page first so the renderer doesn't need to resolve external stylesheets or relative image paths at render time.

Wrap it in your own adapter. Because the package is unmaintained, isolate it behind an interface (Snapshotter) so you can swap in Guzzle + DomCrawler + a modern CSS inliner later without touching call sites.

Gotchas and Tips

It is effectively abandoned (last release Nov 2014). Expect friction on PHP 7.4+/8.x and with modern Symfony components. If composer require fails on dependency conflicts, either use --ignore-platform-reqs in a throwaway context or fork and bump the Symfony/Guzzle constraints. Do not build a critical path on it without a fallback.

No asset downloading. "Flatten to plain HTML" means the HTML is de-externalized for styles/links — it does not necessarily download <img> sources. If you need true offline snapshots, you must crawl and rewrite image/font URLs yourself after flattening.

Relative URL resolution depends on <base> / the source URL. If the original site uses a <base href> or JS-driven navigation, absolute-link rewriting will be wrong. Verify a handful of links in the output before trusting it.

CSS inlining is best-effort. @import, media queries, and CSS custom properties are often not handled the way a browser would. For anything brand-critical, validate visually rather than assuming parity.

Encoding and charset. Old versions assume UTF-8 in places; pages served as ISO-8859-1 or Shift-JIS can come out mojibake. Convert to UTF-8 before/after flattening and check mb_detect_encoding.

Timeouts and memory on large pages. The fetch plus DOM parse can blow up on huge documents. Cap max_execution_time/memory in queued jobs, and set a short HTTP timeout if the underlying client is configurable (often via Guzzle options or by subclassing).

SSRF risk — never flatten user-supplied URLs blindly. This package will happily fetch http://169.254.169.254/ or internal hostnames. Validate the scheme/host, block private IP ranges, and run it in an isolated worker if URLs come from end users.

Debugging. The black-box nature is the main pain. Log the raw fetched HTML before parsing (subclass and override the fetch/parse step, or temporarily var_dump inside flatten()), so you can tell whether a bad result is a fetch issue, a DOM issue, or a CSS issue. Pin exact versions in composer.lock — behavior changes subtly across Symfony DomCrawler versions.

Extension points are thin. There is likely no published config; customization means subclassing Flatten\Flatten and overriding the protected methods for fetching/processing, then binding your subclass in the container. Keep that subclass small and documented so the eventual migration off the package is cheap.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource