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

Laravel Presenter Laravel Package

coderflexx/laravel-presenter

A Laravel package for decorating your models and data with presenters, keeping views clean by moving formatting logic into reusable presenter classes. Easily transform attributes for display without cluttering models or Blade templates.

View on GitHub
Deep Wiki
Context7

Getting Started

coderflexx/laravel-presenter gives you a dedicated class per model for display/formatting logic, so view concerns stop leaking into Blade templates, accessors, and API responses.

Install and orient yourself (5 minutes):

composer require coderflexx/laravel-presenter

Version selection matters more than usual right now:

Your stack Constraint
Laravel 10 / 11 ^2.1 or ^2.2 — both fine
Laravel 12 ^2.2
Laravel 13 ^2.2 (or dev-main until tagged)
PHP 8.1 – 8.4 supported across v2.2.0's CI matrix

Read in this order: the README usage block → src/Presenter.php (the base class and its magic accessors) → the make:presenter stub under src/Commands/. Those three files tell you 90% of the package's behaviour; there is very little surface area to learn.

First use case — a display name and status badge:

  1. Add the package's Presentable trait to the model.
  2. Generate a presenter: php artisan make:presenter UserPresenter.
  3. Add methods to the presenter that read $this->model and return presentation-ready values.
  4. Point the model at the presenter (via the documented property/contract) and use it in Blade:
{{ $user->present()->fullName() }}
<span class="badge">{{ $user->present()->statusLabel() }}</span>

If your app has one recurring complaint like "currency formatting is copy-pasted in eleven Blade files", that is the ideal first migration target: move it into a presenter, delete the copies, and you'll have justified the dependency in an afternoon.

Implementation Patterns

Keep presenters thin and single-purpose. A presenter should answer "how do I show this?" not "what can this model do?". If a method mutates state, saves, dispatches events, or performs authorization, it belongs in a service or policy. Presenters that only read are trivially testable and safe to call from anywhere.

Treat the presenter as the view-model boundary. A workable convention that scales:

  • Model: persistence, relationships, query scopes.
  • Presenter: human-facing strings, formatting, CSS/badge classes, truncated/preview values, localized labels.
  • API Resource: machine-facing shape for JSON consumers.
  • Policy: who may see/edit.

Mixing presenter output into toArray() or API resources is the most common way this pattern rots — presenters are for humans (and often locale-dependent), resources are for contracts.

Inject your formatters rather than calling helpers inline. If you use brick/money, Carbon, or a number formatter, resolve them in the presenter (constructor or method injection through the container) so you can swap behaviour in tests without touching global config.

Localize at the presenter, not in Blade. __('status.paid') inside the presenter means one place to audit when a new locale ships, and Blade stays declarative.

Test presenters directly, no HTTP layer required. Because a presenter is just a class wrapping a model instance, a factory-built model plus a new UserPresenter($user) assertion covers the whole unit. This is where the pattern pays for itself: formatting bugs get caught by fast unit tests instead of view tests.

Mind collections. Presenting inside a @foreach is normal, but make sure the underlying data is eager-loaded before the loop. Presenters are a formatting layer, not a lazy-loading layer — if a presenter method touches $this->model->orders, that's an N+1 waiting to happen in an index page.

Share presenters across similar models where it genuinely fits. A MoneyPresenter or AddressPresenter that works against a small interface is often better than three near-identical per-model presenters — but don't force it; per-model presenters are cheap.

Use it in Livewire/Inertia contexts deliberately. Presenters are plain PHP, so they work fine when building props arrays, but compute once per render and pass the resulting strings down rather than passing the presenter object itself into a JavaScript payload.

Gotchas and Tips

v2.2.0 is a compatibility release, not a feature release. No API changes are advertised, so upgrading from 2.1.x should be a no-op for application code. What actually changed:

  • Laravel 12/13 and PHP 8.2–8.4 support added.
  • PresenterMakeCommand::configure() return type fixed for Symfony/Console in Laravel 13 — only relevant if you subclassed or replaced the generator command; if you did, re-check your override's signature.
  • pestphp/pest-plugin-laravel dropped from the package's own dev dependencies (it blocked Laravel 13). This does not affect your app's dependencies, but if you copied the package's test scaffolding into your own project, you're carrying an outdated setup.
  • CI matrix now covers Laravel 10–13 × PHP 8.1–8.4 — a good signal that the maintenance is real, but it also means the package still supports PHP 8.1, so don't assume 8.2+ language features in any code you share with the package's stubs.

Magic accessors vs. explicit calls. The base presenter proxies property access to methods. That's convenient in Blade and fragile in everything else: IDEs and static analysers won't see the properties, and a typo silently returns null instead of erroring. Prefer explicit ->present()->fullName() in PHP, and if you rely on property syntax in templates, add @method/@property docblocks or a PHPStan stub.

Watch for name collisions with model attributes. A presenter method named name or status that shadows an existing column is a debugging trap — $model->name and $model->present()->name will diverge over time. Prefix presenter methods (displayName, statusLabel, formattedPrice) and the ambiguity disappears.

Don't cache state on the presenter instance. Presenters are frequently instantiated per call; anything you memoize lives only for that call. If you need real caching, do it at the query or response-cache layer, keyed by locale.

Null-safety on optional relations. $this->model->profile->bio inside a presenter will throw on models without a profile — and presenters are exactly the place where you'll be tempted to skip ?->. Decide on a fallback string once and keep it consistent across the app.

Publish the config only if you need it. php artisan vendor:publish for the package's config is optional and, if you do publish, remember php artisan config:cache in deploy scripts — a stale cached config is a classic "works locally" failure.

Generating presenters in CI or Docker builds requires the artisan command to be available; the Symfony/Console fix in this release is precisely the kind of thing that surfaces as a fatal error when running make:presenter under a newer Laravel. If you script make:presenter in scaffolding, pin the package to ^2.2 and add one smoke test that runs the command.

Escape at the boundary. Presenters returning HTML (<span class="badge">…</span>) are convenient but bypass Blade's escaping when printed with {!! !!}. Return plain strings and let the template decide, or keep HTML-returning methods few, named (toBadgeHtml()), and reviewed.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo