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

Parser Laravel Package

orchestra/parser

Orchestra Parser is a lightweight PHP package from the Orchestra Platform that turns structured data formats into usable PHP arrays through a simple, extensible API, making it easy to read and transform configuration or markup in Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with the framework, not around it. The package's majors track Laravel majors, so v10 is presumptively Laravel 12 territory.

composer require orchestra/parser:^10.0

Do not float it (* or dev-main). Pin the major, commit the lockfile, and treat the next bump as a line item on the framework upgrade checklist — not something you discover when composer update breaks CI.

First thing to read is src/, not the README. The surface is deliberately small — a Parser contract, an auto-discovered service provider that binds it into the container, and pluggable handlers per format. Ten minutes in src/ will tell you more than any docs, and it settles the question that actually matters: what formats are registered out of the box. The package blurb advertises XML/YAML/INI/JSON/CSV via a unified parse()/format() API, while some internal write-ups describe it as an XML-only (or even PHP-AST) tool. Confirm against composer.json dependencies and the concrete handler list before anyone designs around it.

First use case — parse at build time, not request time.

use Orchestra\Parser\Parser;

// Resolve through the container; the provider is auto-discovered.
$parser = app(Parser::class);

$contents = file_get_contents(resource_path('blueprints/user.yaml'));

$blueprint = $parser->parse($contents);   // shape: structured array/object
$asJson    = $parser->format($blueprint, 'json'); // convert between formats

If that compiles a blueprint, manifest, stub, or definition into a reusable object, you are squarely in the package's intended lane. If you are parsing a request body or a user-supplied config, you are not — use json_decode, symfony/yaml, or SimpleXMLElement directly and skip the abstraction tax.

Implementation Patterns

Wrap it in an application-owned adapter. This is the single highest-value pattern given the package's size and activity level.

namespace App\Support;

use Orchestra\Parser\Parser;

final class BlueprintCompiler
{
    public function __construct(private Parser $parser) {}

    /** @return array<string, mixed> */
    public function compile(string $path): array
    {
        return once(fn () => $this->parser->parse(file_get_contents($path)));
    }
}

Your app talks to BlueprintCompiler, never to Orchestra\Parser\Parser. When the next major bumps a constraint or shifts output shape, exactly one file changes.

Compile once, cache the result. Parsing is I/O + CPU with no caching of its own. Do it at deploy (php artisan app:compile-blueprints) and persist the structured result — a serialized array, a generated PHP class, or a Laravel config cache file. Never re-parse the same artifact on every request.

Use it for code generation and scaffolding. This is where it earns its keep day-to-day: definition files → generated classes, stubs → rendered templates, manifests → registered providers. Pair it with artisan commands so output is reproducible and diffable.

Golden-file tests are non-negotiable. Store fixtures in tests/Fixtures/parser/ and assert on the exact structure, not a subset:

public function test_user_blueprint_compiles(): void
{
    $this->assertSame(
        require __DIR__.'/Fixtures/expected/user_blueprint.php',
        app(BlueprintCompiler::class)->compile(resource_path('blueprints/user.yaml')),
    );
}

assertSame with a full expected array is what catches silent output drift — the failure mode that ships broken generated code without anyone noticing.

Swap it out in tests.

$this->instance(Parser::class, new class implements Parser {
    public function parse($content) { return ['id' => 'stub']; }
    public function format($data, $format) { return '{}'; }
});

Because you injected the contract, this is a two-liner.

Gotchas and Tips

Single-item vs. list shape changes. The classic parser trap: a repeated element with one occurrence may come back as a scalar, with two occurrences as an array. Guard generated code with normalization (Arr::wrap) or golden-file tests will not save you — they'll just fail loudly in prod when the count changes.

Everything is a string until you say otherwise. Parsed values arrive untyped. Cast at the boundary ((int), filter_var($v, FILTER_VALIDATE_BOOLEAN)) inside your adapter, once, rather than sprinkling casts at call sites.

XML specifics worth testing explicitly: attributes vs. child nodes, namespaces, CDATA sections, self-closing tags, and whitespace around text nodes. All four behave differently across parsers and are where "it worked locally" comes from.

XXE. If you parse XML from anywhere you don't fully control, verify external entity loading is disabled. Check the underlying loader configuration — do not assume.

Error handling is per-handler, so wrap defensively. Malformed input throws, and the exception type may differ by format. Catch broadly at the adapter boundary and rethrow as a domain exception so callers get one predictable failure.

Don't route config or JSON parsing through it. If the answer is json_decode or config(), this package adds an indirection and a version constraint for nothing. Same for reflection — use ReflectionClass.

Vendor risk is real but bounded. Zero dependents and sparse release notes mean there is no downstream community to diagnose breakage for you, and no external validation of the upgrade path. Small blast radius if it fails, small safety net when it does — which is exactly why the adapter and the pinned constraint matter more here than they would with a mainstream package.

Extension points: custom handlers are the escape hatch when you need a format the package doesn't ship. Register it rather than forking; forking a thinly-maintained package is how you end up owning it permanently.

Upgrade ritual, every framework cycle: branch → bump the major → composer why orchestra/parser → full test suite → golden-file diff → stage → deploy with lockfile rollback ready. It's a small, repeating cost; budget it as such rather than pretending it's a one-off.

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.
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
nodisrupt/laravel-agent
sierratecnologia/media-manager