laravelium/feed
Generate RSS 2.0 and Atom 1.0 feeds with a framework-agnostic PHP library for Laravel, Symfony, and any project. Includes built-in caching, custom views, dependency injection, and full test coverage.
Architecture fit
FeedCacheInterface, FeedConfigInterface, FeedResponseInterface, FeedViewInterface — which map cleanly onto Laravel's container, cache repository, and Blade/view factory. That is the correct abstraction boundary for a library that must serve Laravel, Symfony, and vanilla PHP from one codebase.ServiceProvider, no auto-discovery, no facade, no publishable config file. FeedFactory::create() is a static constructor. In a Laravel codebase that means we own the wiring: a FeedServiceProvider, a config array, and a cache adapter that delegates to Illuminate\Contracts\Cache\Repository. That is a half-day of glue, but it is our code, not the vendor's — and it becomes our maintenance burden on every major Laravel upgrade.isCached()/clearCache(), but never shows a shipped Laravel cache adapter or the cache-key strategy. A TPM must treat caching as unproven until spike-verified, not as a delivered feature.render() returning mixed (framework response or XML string depending on adapter set) is a real API-design smell. It pushes a runtime type check into every call site and makes static analysis weaker exactly where correctness matters (HTTP response construction).Integration feasibility
composer require rumenx/php-feed is the whole setup. No migrations, no schema, no external service, no queue worker. This is about as low-friction as a dependency gets.laravelium/feed, while the repository, badges, install command, and namespace (Rumenx\Feed) all belong to rumenx/php-feed. laravelium/feed is a well-known older Laravel feed package with a different namespace and a different maintenance history. These are not the same artifact. Before any engineering hour is spent, we must confirm which Composer package we are actually evaluating, which namespace we get, and whether the laravelium name is a fork, a rename, or an error in the intake record. Shipping on the wrong assumption here means a dependency we cannot patch and cannot explain to a security reviewer.Technical risk
| Risk | Severity | Notes |
|---|---|---|
| Package identity / namespace ambiguity | High | Blocker until resolved; see above |
| Zero dependents on Packagist | High | No downstream production signal at all |
| Bus factor of one | High | Single maintainer (RumenDamyanov); releases are dependabot-driven |
| v1.0.x only, ~3 releases | Medium | API not yet battle-hardened; expect breaking change at 2.0 |
| No JSON Feed, no podcast/iTunes namespaces | Medium | Blocks two of the most common syndication asks |
No conditional-GET (ETag / Last-Modified / 304) |
Medium | Real scaling and bandwidth cost on hot feeds |
| No WebSub / PubSubHubbub | Low-Medium | Acceptable if we do not need push syndication |
render(): mixed |
Low | Friction, not failure; mitigated by a thin internal wrapper |
Key questions for engineering before we commit
laravelium/feed or rumenx/php-feed? Is there a maintained fork lineage?pubdate inputs normalized across DateTimeInterface, Carbon, and strings, and what timezone does the renderer assume?Stack fit
Reasonable but not idiomatic. It is a PHP library that happens to run in Laravel, not a Laravel package. That is fine — sometimes preferable — but it means we adopt the wiring cost. Concretely, we would add:
FeedServiceProvider binding interfaces to Laravel implementations (CacheRepositoryAdapter, ConfigRepositoryAdapter, BladeViewAdapter).config/feed.php with channel defaults (title, link, language, date format, item limit).FeedResponse wrapper that resolves the mixed return into a real Illuminate\Http\Response, so controllers never touch the ambiguity.That wrapper layer is the key decision: it isolates ~150 lines of ours from vendor churn and makes a future swap to spatie/laravel-feed or a hand-rolled renderer a contained change rather than a grep-and-replace across the codebase.
Migration path
laravelium/laravel-feed (if that is the incumbent): near drop-in conceptually — both are channel + items + render — but namespaces and the item array shape differ. Budget ~1 day per feed endpoint for port plus golden-file regression tests against current XML output.spatie/laravel-feed: this is a downgrade in Laravel ergonomics (we lose the service provider, the Route::feeds() macro, and the auto-configured routes) in exchange for framework agnosticism we do not need if we are a Laravel shop. Migration only makes sense if a non-Laravel PHP service also needs feeds.Compatibility
Sequencing
Maintenance
The dominant cost is not the dependency — it is the glue we write around it. Our adapters and wrapper become first-class code with their own tests and their own upgrade obligations on every Laravel major. Budget a recurring ~2 days per year for dependency bumps plus the annual Laravel upgrade cycle, on top of the initial ~1 week. The vendor's own release cadence appears dependabot-driven (v1.0.2 is a dev-dependency bump), which means we should not expect proactive fixes; we should expect to pin versions and patch locally if needed. Forking is cheap here (MIT, small surface), and we should treat "we can fork this in an afternoon" as an explicit risk mitigation rather than a contingency.
Support
Single-maintainer, no commercial backing, no SLA, no security disclosure timeline beyond a SECURITY.md file. That is acceptable for a non-critical-path library with no auth, no network I/O, and no data persistence — the blast radius of a vulnerability is limited to XML output encoding. It is not acceptable if feeds become a contractual deliverable (paid subscription feeds, partner syndication). Escalate to a vendor-risk exception with a named internal owner and a documented fork plan.
Scaling
Feeds are read-heavy, bursty, and read by bots more than humans. Without ETag/304 handling the package will regenerate and re-serialize full XML on every poll — a naive aggregator hitting a 50-item Atom feed every 15 minutes across a few thousand subscribers is real egress. Mitigations: put a CDN or Cache-Control in front of the endpoint, wrap render() output in a cache layer keyed on content version, and add our own Last-Modified handling in the wrapper since the package does not provide it. Caching is therefore an our-responsibility concern despite the README's framing. At our expected volume this is manageable, but it is not free, and it is not a feature of the package.
Failure modes
pubdate handled as string in one code path and DateTime in another. Lower severity, but it produces feeds with wrong timestamps that are hard to notice.Ramp-up
Very low for any PHP developer: the public API is eight methods. A mid-level engineer is productive in under an hour. The learning cost sits entirely in feed correctness — XML escaping, RFC 822 vs RFC 3339 date formats, required vs optional Atom elements — not in the library. Plan to have one engineer own feed-spec literacy, because "it rendered without throwing" is not the same as "it validates."
Bottom line for the decision log. This is a small, clean, well-tested library solving a small, well-understood problem with a crowded field of more-adopted alternatives. The opportunity score of 2.77 reflects that accurately. Adopt it if we have genuine multi-framework PHP needs or want to replace untested in-house XML code; otherwise spatie/laravel-feed gives us the Laravel ergonomics we are currently doing without. The evaluation is blocked until the laravelium/feed vs rumenx/php-feed identity question is resolved — do not spend engineering hours ahead of that answer.
How can I help you explore Laravel packages today?