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

Fast Attributes Laravel Package

lee-to/fast-attributes

lee-to/fast-attributes is a lightweight Laravel package for fast, expressive model attribute handling. It reduces boilerplate around accessors and casts, keeping Eloquent models clean, readable, and efficient—ideal for apps that want simpler model definitions without sacrificing performance.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and verify compatibility first. The package targets PHP 8.1+ and "modern Laravel," so check composer.json inside the repo for the actual illuminate/* constraint before assuming your version is supported:

composer require lee-to/fast-attributes

There is no documented service provider step or publishable config in the description — it advertises "drop-in Eloquent integration," so most likely the attribute classes work as soon as the autoloader picks them up. Confirm by grepping the package for ServiceProvider and config/.

Where to look first, in this order:

  1. src/ — the attribute class names (Cast, Accessor, Mutator, or whatever they're actually called). The description does not name them, so read the source rather than guessing from the README.
  2. tests/ — for a 2-star package with a single release (Feb 2025), the test suite is the de facto documentation. Look for a fixture model showing attributes in use.
  3. The cache/resolver class — anything mentioning "cached attribute maps" tells you whether caching is per-request, per-process, or persisted.

First use case: migrate one awkward model, not your whole app. Pick a model with two or three verbose accessors and convert only those:

// Before
protected $casts = ['published_at' => 'datetime'];

public function getSlugAttribute(): string
{
    return Str::slug($this->title);
}

// After (attribute names illustrative — verify against src/)
class Post extends Model
{
    #[Cast('datetime')]
    protected $published_at;

    #[Accessor]
    public function slug(): string
    {
        return Str::slug($this->title);
    }
}

Run your existing model test suite against it. If $post->slug and $post->published_at still behave identically, you've validated the integration and can expand.

Implementation Patterns

Incremental, per-model adoption. Because the package claims to be drop-in, the sane workflow is: convert one model, run tests, ship, repeat. Do not batch-convert every model in a PR — if the cached attribute map has an edge case with inheritance or traits, you want the blast radius to be one model.

Keep native $casts for anything the package doesn't cover. The package handles casts, accessors, and mutators; it does not claim to replace $fillable, $hidden, $appends, observers, or query scopes. Leave those untouched and let the two systems coexist. Verify precedence explicitly: if you declare the same property in both $casts and an attribute, determine which wins by testing, and then never do it again.

Use it where the declarative form earns its keep. Attributes are most valuable for:

  • Computed properties that would otherwise be a one-line getXAttribute() boilerplate stack.
  • Per-property casts that sit next to the property declaration, which reads better on models with 15+ columns.
  • Derived values you want visible in the class body rather than 200 lines down under // Accessors.

They are least valuable for complex mutators with multiple branches — those belong in a dedicated value object or a custom cast anyway.

Pair it with a base model or trait if you need shared behavior. If several models define the same computed attribute, put it on a trait and let each model use the trait. Check whether the attribute map resolves through traits before relying on this — reflection-based scanners vary in whether they walk parent classes and traits.

Anchor computed properties with $appends. An attribute-defined accessor is invisible to toArray() unless the property name is in $appends. This is ordinary Eloquent behavior, but it is the single most common "the package is broken" false alarm:

protected $appends = ['slug'];

Write a small contract test per converted model. Assert the accessor reads correctly, the mutator round-trips, and toArray() includes what you expect. This is your safety net given the package's thin ecosystem.

Gotchas and Tips

Cached attribute maps are a deploy-time concern. The package advertises "per-model cached attribute maps." Find out what backs that cache — an in-process static array is free but must be treated as immutable after boot; a persisted cache needs clearing on deploy. If it's persisted, add the clear command to your deploy script before you need it in production.

Long-running workers and Octane. If the map is memoized in a static property, code that generates models dynamically or uses class_alias can poison it. Test under octane:start (or at minimum a queue worker processing many models) before assuming parity with php artisan serve.

Attribute inheritance is the likeliest sharp edge. PHP attributes are not inherited by default. If BaseModel declares #[Cast('array')] on a property and ChildModel extends it, the child may not see the attribute unless the scanner uses ReflectionAttribute::IS_INSTANCEOF and walks the class hierarchy. Test this early — it determines whether you can centralize casts on a base model at all.

IDE and static analysis need help. The description promises "IDE- and static-analysis-friendly," but PHPStan and Psalm generally resolve magic properties through @property docblocks or the larastan extension, not attributes. Keep @property annotations on the model class even after converting; you lose nothing and you keep autocomplete.

Escape hatch when things go wrong. If a converted accessor returns null or throws, revert that single property to a plain getXAttribute() method and confirm it works. That isolates whether the problem is your attribute definition, the scanner, or the cache — three different fixes. Bypass the cache by restarting the process before you go spelunking in the source.

Budget for maintenance risk. Two stars, zero dependents, one release in early 2025. Pin the exact version in composer.json ("lee-to/fast-attributes": "1.0.0" rather than ^1.0), keep the conversion surface small, and be prepared to inline the accessors back if the package goes unmaintained. The migration cost in both directions is low precisely because you converted incrementally — preserve that property.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle