Weave Code
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 Computed Attributes Laravel Package

korridor/laravel-computed-attributes

Adds “computed attributes” to Laravel models, letting you define dynamic/derived properties that behave like normal attributes (including access/casting/serialization) without storing them in the database. Useful for clean model APIs and reusable calculations.

View on GitHub
Deep Wiki
Context7
## Getting Started

### **First Steps**
1. **Installation**
   ```bash
   composer require korridor/laravel-computed-attributes
   php artisan vendor:publish --provider="Korridor\ComputedAttributes\ComputedAttributesServiceProvider" --tag="config"
  • Verify config/computed-attributes.php exists (default settings work for most cases).
  • Note: Officially supports Laravel 10/11/12/13 (check releases).
  1. Define a Computed Attribute Add to your Eloquent model:

    use Korridor\ComputedAttributes\HasComputedAttributes;
    
    class Product extends Model
    {
        use HasComputedAttributes;
    
        protected $computedAttributes = [
            'formatted_price' => function () {
                return '$' . number_format($this->price, 2);
            },
        ];
    }
    
  2. First Use Case

    $product = Product::find(1);
    $product->formatted_price; // Computes and caches (if enabled)
    $product->save();          // Persists to DB
    

Implementation Patterns

1. Core Workflows

A. Basic Computation

protected $computedAttributes = [
    'discounted_price' => function () {
        return $this->price * (1 - $this->discount / 100);
    },
];

B. Conditional Logic

'status_badge' => function () {
    return $this->is_active ? 'badge-success' : 'badge-danger';
},

C. Dynamic Dependencies

'tax_amount' => function () {
    return $this->price * $this->getTaxRate();
},

D. Caching Control

'volatile_data' => [
    'computation' => fn() => $this->fetchExternalData(),
    'cache' => false, // Disable caching
],

2. Integration Patterns

A. Model Events

Trigger recomputation on updates:

protected static function booted()
{
    static::updating(function ($model) {
        $model->recomputeComputedAttributes();
    });
}

B. API Responses

Auto-include in JSON:

protected $appends = ['formatted_price'];

C. Mass Assignment

Allow computed attributes in fillable:

protected $fillable = ['*']; // Or explicitly list

D. Database-Level Hybrid

Use virtual columns (MySQL 5.7+) alongside PHP computations:

// Migration
$table->virtualAs('CONCAT(name, " (", category, ")")')->storedAs('full_name');

3. Advanced Patterns

A. Shared Computations

Use traits for reusable logic:

trait ComputesShippingCost
{
    public function getShippingCostAttribute()
    {
        return $this->weight * 0.50;
    }
}

B. External Data Fetching

Cache API responses:

'weather' => [
    'computation' => fn() => Cache::remember("weather_{$this->id}", 3600, fn() =>
        Http::get("api.weather/{$this->location}")->json()
    ),
    'cache' => true,
],

C. Soft Deletes

Recompute on restore:

protected static function booted()
{
    static::restored(function ($model) {
        $model->recomputeComputedAttributes();
    });
}

D. Queue Jobs for Heavy Computations

$model->afterSave(function ($model) {
    ComputeHeavyAttribute::dispatch($model, 'complex_value');
});

Gotchas and Tips

1. Common Pitfalls

A. Circular Dependencies

  • Problem: a depends on b, which depends on a.
  • Fix: Use cache: false or restructure logic.

B. Performance Overhead

  • Problem: Heavy computations slow down bulk operations.
  • Fix:
    • Disable caching for non-critical attributes.
    • Use queue jobs for expensive computations.

C. Database Schema Mismatches

  • Problem: Computed value exceeds column length.
  • Fix: Adjust column type (e.g., text) or sanitize values:
    'truncated_name' => fn() => Str::limit($this->full_name, 50),
    

D. Serialization Issues

  • Problem: Computed attributes missing in JSON.
  • Fix: Add to $appends:
    protected $appends = ['formatted_price'];
    

2. Debugging Tips

A. Log Computations

'debug_value' => [
    'computation' => fn() => Log::debug('Computing debug_value'),
    'cache' => false,
],

B. Check Cache State

$model->isComputedAttributeCached('full_name'); // true/false

C. Force Recompute

$model->recomputeComputedAttribute('formatted_price');

3. Configuration Quirks

A. Global Cache TTL

Set in config/computed-attributes.php:

'default_cache_ttl' => 3600, // 1 hour

B. Exclude Attributes

'skip_on_create' => [
    'computation' => fn() => 'value',
    'skip_on_create' => true,
],

C. Custom Storage

Override storage (e.g., JSON column):

use Korridor\ComputedAttributes\StoresComputedAttributesInJson;

class Product extends Model
{
    use HasComputedAttributes, StoresComputedAttributesInJson;
}

4. Extension Points

A. Custom Computation Types

ComputedAttributes::extend('custom', function ($model, $attribute) {
    return strtoupper($model->{$attribute});
});

Usage:

'uppercase_name' => ['type' => 'custom'],

B. Event Hooks

ComputedAttributes::computing(function ($model, $attribute) {
    Log::info("Computing {$attribute} for {$model->id}");
});

C. Database Drivers

Extend for PostgreSQL/SQLite:

// app/Providers/ComputedAttributesServiceProvider.php
public function register()
{
    if (config('database.default') === 'pgsql') {
        $this->app->bind('computed-attributes.driver', \App\Services\PostgresDriver::class);
    }
}

5. Testing Strategies

A. Unit Tests

Mock computations:

$model->shouldReceive('computeFormattedPrice')->once()->andReturn('$10.00');

B. Feature Tests

Test persistence:

$model->formatted_price = '$5.00';
$model->save();
$model->refresh();
$this->assertEquals('$5.00', $model->formatted_price);

C. Edge Cases

  • Test with null values.
  • Verify behavior during model creation vs. updates.

6. New in v3.3.0+

A. Laravel 13 Support

  • Officially compatible with Laravel 13’s latest features (e.g., improved dependency injection).
  • Impact: No breaking changes; existing code works as-is.

B. PHPStan Integration

  • Static code analysis in CI catches type-related issues early.
  • Impact: Reduces runtime errors and improves maintainability.

C. Updated Dependencies

  • GitHub Actions v6, Codecov v6, etc.
  • Impact: More reliable CI/CD pipelines.

D. Validation Command

Check computed attribute consistency:

php artisan computed-attributes:validate --model=Product

E. Scoped Commands

Optimize queries with ->with():

php artisan computed-attributes:validate --model=Product --scope="with(relationship)"

7. Laravel 13-Specific Tips

A. Use New Model Macros

Combine with Laravel 13’s macroable traits:

Product::macro('recomputeAll', function () {
    return $this->each->recomputeComputedAttributes();
});

B. Leverage Model Observers

Use Laravel 13’s improved observer syntax:

Product::observe(ProductObserver::class);

C. Type Safety

Leverage PHP 8.2+ return types:

public function getFormattedPriceAttribute(): string
{
    return '$' . number_format($this->price, 2);
}

D. Testing with Pest

it('persists computed attributes', function () {
    $product = Product::factory()->create(['price' => 100]);
    $product->save();
    $this->assertDatabaseHas('products', [
        'id' => $product->id,
        '
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata