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

Model Attributes Laravel Package

worksome/model-attributes

A Laravel package for defining typed, castable attributes on Eloquent models, cutting casting boilerplate and keeping model data consistent.

View on GitHub
Deep Wiki
Context7

Getting Started

worksome/model-attributes lets you move the logic that would otherwise live in Eloquent accessors/mutators (getFooAttribute / setFooAttribute) into small, reusable, independently testable attribute classes that are declared on the model. If you have ever copy‑pasted the same "format this column" or "normalise this input" logic across three models, this package is the replacement.

Requirements for v0.2.0

  • PHP 8.2+ (bumped from 8.1 in this release — check your CI matrix, Docker base image and platform config in composer.json before upgrading).
  • Laravel 10 (illuminate/* ^10.0 added in this release). If you are still on Laravel 9 or PHP 8.1, pin worksome/model-attributes:^0.1.

Install

composer require worksome/model-attributes

There is nothing to publish — no config file, no migration, and the service provider is auto-discovered.

Where to look first

  1. The package's own attribute base class / contract — that is your extension point.
  2. The README's example attribute, which shows the get/set halves of the lifecycle.
  3. A single model in your app that already has a messy accessor, e.g. getPhoneAttribute().

First use case

Take one accessor + mutator pair on your User model:

// Before
public function getPhoneAttribute($value): ?string
{
    return $value ? preg_replace('/\s+/', '', $value) : null;
}

Extract it into one attribute class, register it on the model, and delete both methods. You get a class you can unit test without touching the database, and a second model can reuse it by adding one line.

Implementation Patterns

One attribute class = one concern. Keep classes tiny and pure: normalise on set, format on get, nothing else. No queries, no auth(), no now() — the moment an attribute needs the container it becomes as hard to test as the accessor it replaced.

Reuse is the main win. Value-like attributes (phone numbers, money, slugs, enum-ish strings, JSON blobs) are the sweet spot. Build a small internal library of them (app/Attributes/) and treat them as shared infrastructure rather than per-model helpers.

Compose with casts, don't replace them. Casts are the right tool for type conversion and serialisation of whole columns; model attributes are the right tool for behavioural transformation on read/write. Use both on the same column when a cast handles the type and an attribute handles the formatting.

Test through the model, not just the class. A cheap feature test that creates a model via factory, sets the attribute and asserts both the database value and the hydrated value catches the integration mistakes (wrong registration, wrong column name) that a pure unit test cannot.

Keep models declarative. Put the registration in one obvious block/trait on the model so a reviewer can see at a glance which attributes a model participates in. If you have ten of them, group them behind a small trait per domain concept.

Factories and seeders. Since the setter side runs on assignment, factory data gets normalised for free — which is usually what you want, but make sure the test asserts the normalised form, not the raw input you passed in.

Gotchas and Tips

The PHP 8.2 bump is the real breaking change in v0.2.0. Nothing in the public API changed, but the floor moved: a project on 8.1 will silently fail to resolve, and CI images lag behind locally more often than you'd expect. Run composer why-not php 8.2 before upgrading and verify config.platform.php isn't pinned lower. composer update worksome/model-attributes -W is the cleanest way to see the constraint failure early.

Attributes are PHP-level only — they do not exist in SQL. You cannot use them in where(), orderBy() or raw queries. If a value is stored in a transformed shape, query with the stored shape (or scope it), and don't assume the attribute output matches the column.

Watch for read-triggering-read loops. An attribute that internally reads another attribute on the same model is fine, but an attribute that reads itself (or two attributes that read each other) will recurse until the stack blows. Prefer reading $this->getRawOriginal('column') inside the model when a raw value is needed.

Null and empty strings. Decide explicitly whether null passes through untouched or is normalised. Silent coercion of null into '' is the most common cause of "why is this column not nullable anymore" surprises.

Serialisation. toArray() / toJson() reflect whatever Laravel sees after the getter side runs. If an API contract depends on the raw value, assert it in a test rather than assuming.

Performance. Getter logic runs on every attribute access, including inside loops and Blade templates. Keep it allocation-light; if it does real work, cache the result on the instance rather than recomputing per read.

Debugging. If an attribute appears not to run, check registration first (typo in the column name, attribute registered after the value was already hydrated), then whether another cast is applied to the same key — two mechanisms on one column is the usual culprit. $model->getRawOriginal('column') versus $model->column is the fastest way to tell which layer is doing what.

Extension points. Subclass the package's base attribute when you need shared behaviour (trimming, null policy, logging); keep any app-wide conventions in that one subclass so the dozens of concrete attributes stay one-liners.

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.
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo