mv/mv-blog-bundle
MV Blog Bundle is a Symfony package for adding blog functionality to existing applications. It provides a straightforward way to manage posts and integrate common blogging features, helping developers reduce setup effort and ship a simple blog backend faster.
First, the framing: this is a Symfony 2.2–2.5 bundle, not a Laravel package. There is no composer require path into a Laravel app — Composer will try to resolve symfony/*@~2.2 constraints against the symfony/*@^6/^7 that Laravel already pulls and fail before any code runs. "Getting started" here means reading the source as a reference implementation, then rebuilding the concepts natively. Budget half a day for the read, not a sprint for integration.
Step 1 — Clone and orient (30–60 min). The repo is small. Read in this order:
Entity/ — Post, Category, Tag, Comment. This is the entire value proposition: field lists, relationships, publishing state, slug handling.Controller/ — how posts are listed, viewed by slug, archived by category/tag, and commented on. Note the routing conventions.Form/ — what fields are editable and what validation exists.Resources/config/ and Resources/views/ — service wiring and Twig layout, so you can see what a "minimum viable blog" UI actually looks like.Step 2 — Write a one-page domain spec. Post fields, taxonomy, comment threading (parent/child vs flat), publish/draft states, slug generation and uniqueness, and archive grouping. This document is the deliverable; the code is not.
Step 3 — Pick your first use case. The realistic one is a small internal or company blog: post CRUD, category browse, tag filter, dated archive, threaded-ish comments. Build it in Laravel as:
posts (title, slug unique, body, excerpt, status enum, published_at, author_id, timestamps, softDeletes)categories, tags, category_post, post_tagcomments with parent_id, approved flag, and an author identity strategy{post:slug} route-model bindingStep 4 — If and only if you have a live Symfony 2.x app that must consume this bundle: register it in AppKernel, import its routing.yml, and run doctrine:schema:update --force in a throwaway environment first. That is the only scenario where the bundle itself runs.
Reference-extraction pattern (the only sane one for Laravel). Treat the repo as read-only design input and map concept-for-concept:
| Bundle artifact | Laravel rebuild |
|---|---|
| Doctrine entity + annotations | Eloquent model + migration |
Post publishing state |
status enum cast + published_at |
services.xml DI wiring |
Service provider bindings / action classes |
| Symfony Form type | FormRequest + validation rules |
| Twig templates + layout | Blade views + @extends layout |
routing.yml |
routes/web.php resource routes |
| Bundle config tree | config/blog.php |
| Repositories | Eloquent scopes / query objects |
Slug routing. The bundle's slug-based URLs map directly to Laravel route-model binding. Enforce uniqueness at the DB level and decide now how renames behave (301 to the new slug vs. immutable slugs). This is the single most common thing to regret later.
Publishing states. Model draft/published as an enum plus a nullable published_at, then add a scopePublished() that checks both. The bundle's binary state is a floor, not a ceiling — add scheduling and archived states on day one; retrofitting them means data migration.
Taxonomy. Categories are one-to-many-in-practice (usually one primary category) and tags are many-to-many. Don't copy the bundle's symmetric treatment blindly; pick per your browse UX.
Comments. If you implement comments at all, treat them as user-submitted content from the first commit: approved boolean defaulting false, rate limiting, HTML sanitization, and an author identity that does not silently depend on a full user account. Threading via parent_id with a depth cap is sufficient; the nested-set approach is not worth it at blog scale.
Admin surface. Skip hand-rolled CRUD. Filament or Nova gives you post/tag/category management, publishing toggles, and comment moderation in a fraction of the time. The bundle's admin controllers are a checklist of what to expose, not how.
If you must run it in Symfony 2.x: override templates by placing files under app/Resources/MvBlogBundle/views/ (bundle inheritance via MvBlogBundle:... is deprecated as of 2.4). Wire config in config.yml under the bundle's config key and clear the cache after every change.
The install failure is the expected outcome, not a problem to solve. Any attempt to composer require mv/mv-blog-bundle in a Laravel app will fail resolution. Don't spend time on --ignore-platform-reqs, replace hacks, or a "shim" service provider — the shim would be larger than the feature.
PHP 8 is a wall. The 2.2–2.5 era assumes PHP 5.3.3+ idioms: each(), create_function(), dynamic property assignment, and old Doctrine DBAL/annotations. These are fatal errors or deprecations on 8.x. If you're only reading the code, this is irrelevant; if you're trying to run it, it's a rewrite.
Check composer.json for hidden coupling before drawing conclusions. Bundles of this vintage often assume FOSUserBundle for authorship and StofDoctrineExtensionsBundle for Sluggable/Timestampable. If either is present, the "simple blog" is actually three abandoned packages, and your domain spec needs to note that slugging is your responsibility in the rebuild.
No security process exists. Eight stars, zero dependents, supported framework long EOL. Any public-facing admin or comment surface is unpatchable at the framework layer. This is a hard stop for customer-facing work and a documented risk for internal use — put it in the decision log so it isn't re-litigated in six months.
Slug and delete interaction. The 2013-era schema typically has no soft deletes. Rebuild with softDeletes() and a unique slug index, and decide whether trashed posts free their slug. Getting this wrong shows up as 500s on publish months later.
Comments are the liability, not the feature. User-submitted content without moderation, spam controls, or a retention policy is the part of this bundle you least want to inherit. If the content need is a company news page, ship without comments.
Timebox the spike with a hard stop. One to two days to extract the model; if it feels longer than that, the answer is "build a thin Post/Category/Tag module," which is a well-understood 1–2 week effort for a competent Laravel developer — the real cost either way is the build, not the bundle.
Extension points aren't worth preserving. There's no event system, no meaningful DI tags, and no maintenance branch. If you fork for a legacy Symfony app, you own every future PHP upgrade as a manual remediation. Prefer rebuilding on the host framework's cadence.
Debugging, if you do run it on Symfony 2.x: use the dev profiler for routing and Doctrine queries, doctrine:schema:validate before and after schema changes, and always cache:clear after config edits — the config tree is compiled, so stale caches produce misleading errors.
Archive the reference with a note. After extraction, record in your ADR/decision log that the repo was evaluated, what was borrowed (the domain model), and why it wasn't adopted. That's the cheapest way to stop the next developer from repeating the evaluation.
How can I help you explore Laravel packages today?