liip/vie-bundle
Symfony bundle that integrates VIE.js and Create.js for in-place, semantic editing of RDFa-annotated content. It provides server-side support for loading and persisting editable resources, so front-end editors can work directly with your application's data.
Read this paragraph before installing anything. liip/vie-bundle is a Symfony 2-era bundle, archived, and self-deprecated in favor of SymfonyCmfCreateBundle — which is itself dormant. There is no Laravel service provider, no facade, no config publish, and no auto-discovery. "Getting started" here really means "getting oriented before you decide to replace it" or "getting an inherited install onto modern PHP long enough to migrate off." Treat the code as a reference implementation, not a dependency.
Minimal steps if you are inheriting an install
composer.json in the repo. Note the Symfony and jQuery pins. On modern PHP you will almost certainly need composer install --ignore-platform-reqs, and you should expect constraint collisions with laravel/framework's pinned symfony/* components if you try to co-install.DependencyInjection/Configuration.php. This is the fastest map of the bundle's entire surface: entity/type mappings (RDFa types → PHP classes), backend selection, and the edit route. Everything else is plumbing behind these keys.Resources/config/. The service definitions tell you what is wired to what — the REST controller, the VIE/Create.js asset configuration (Assetic-era), and the persistence adapter (PHPCR-ODM / Jackalope).PUT from Create.js. That request/response shape — load resource, edit in place, PUT the JSON-LD back — is the only part of this bundle worth preserving.First useful use case
The single highest-value first use case is extracting the wire contract. Hit an edit, capture the PUT payload (the JSON-LD with @type, @id, and property values), and document it. That shape is what you will reimplement in a Laravel controller. Everything else about the bundle — the DI wiring, the asset pipeline, the PHPCR persistence — is Symfony- and JCR-specific and does not translate.
Where to look first, in order
DependencyInjection/Configuration.php — the config surface.Resources/config/ — service wiring.Resources/public/ or asset config — the VIE/Create.js bootstrap (dead-end, but instructive).composer.json — the abandoned transitive tree, and the reason nothing below will be easy.Because this bundle is not Laravel-installable in any realistic sense, the day-to-day patterns below are the ones a Laravel developer actually uses the repository for: as a specification to reimplement, and as compatibility scaffolding when inheriting.
Pattern 1 — Reimplement the write contract natively in Laravel
The bundle's core loop is: client loads a resource → user edits inline over RDFa → client PUTs JSON-LD → backend persists. That maps cleanly to Laravel:
Route::get('/content/{id}', [ContentController::class, 'show']) returns the resource with its @type/@id/properties serialized.Route::put('/content/{id}', [ContentController::class, 'update']) accepts the JSON-LD payload.FormRequest validates the payload (type matches, properties are in the allowed set for that type, lengths/format).Policy authorizes the edit against the resource.content_resources / content_attributes schema, or a JSON column if you do not need per-attribute querying.This is a few hundred lines, and it is ordinary Laravel — testable, hireable, maintainable. It is strictly better than a port.
Pattern 2 — Use the bundle's type mapping as your validation schema
Configuration.php maps RDFa types (e.g. schema:Article, sioc:Post) to PHP entities and allowed properties. In Laravel, that mapping becomes your FormRequest rules and your serialization whitelist. Keep the mapping as a config file (config/content_types.php) so it is data, not code. This preserves the one genuinely reusable concept: type-scoped attribute whitelists.
Pattern 3 — Integration when you must co-exist with a legacy Symfony app
If a Symfony instance running this bundle must stay up while you migrate:
Pattern 4 — Front-end replacement, decoupled from the content model
The RDFa/semantic-markup output is a data-modeling concern and can be generated independently of whatever editor you choose. Use a maintained editor (TipTap/ProseMirror, Lexical, Editor.js) or a headless CMS admin, and emit schema.org/JSON-LD from the persistence layer on render. This is the pattern that makes the VIE lineage unnecessary — the semantic requirement and the authoring tool are separable.
Workflow summary
ContentController + FormRequest + Policy.Package-level pitfalls
composer require this into a Laravel app. Constraint resolution will deadlock against Laravel's pinned symfony/* components, and where it succeeds it will break unrelated dependency updates. The transitive tree (CreatePHP/CreateBundle, PHPCR, Jackalope, Midgard RDFa) is uniformly abandoned.--ignore-platform-reqs is a smell, not a fix. It gets you past install and into runtime breakage. Use it only in a throwaway environment for contract extraction.Debugging tips
@id and follow it into the PHPCR document manager. The mapping between @id and PHPCR path is where most confusion lives.Config quirks
Configuration.php, it is not configurable without a fork.Extension points (and their limits)
Laravel-specific guidance
SymfonyCmfCreateBundle is not a safe landing spot — check its maintenance status independently.The bottom line for a Laravel developer's day-to-day
You will not be using this package day-to-day. You will use it once: as a reference during a migration away from it. Budget a 1–2 day spike to extract the JSON-LD write contract and confirm composer resolution fails, then build the equivalent natively. Do not name an owner for a fork — name an owner for the migration instead.
How can I help you explore Laravel packages today?