PHP code example of openplain / laravel-flowfield

1. Go to this page and download the library: Download openplain/laravel-flowfield library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

openplain / laravel-flowfield example snippets




namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Openplain\FlowField\Attributes\FlowField;
use Openplain\FlowField\Concerns\HasFlowFields;

class Customer extends Model
{
    use HasFlowFields;

    public function ledgerEntries()
    {
        return $this->hasMany(CustomerLedgerEntry::class);
    }

    #[FlowField(method: 'sum', relation: 'ledgerEntries', column: 'amount')]
    protected function balance(): Attribute
    {
        return Attribute::make(get: fn () => null);
    }

    #[FlowField(method: 'count', relation: 'ledgerEntries')]
    protected function entryCount(): Attribute
    {
        return Attribute::make(get: fn () => null);
    }
}



namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Openplain\FlowField\Concerns\InvalidatesFlowFields;

class CustomerLedgerEntry extends Model
{
    use InvalidatesFlowFields;

    protected array $flowFieldTargets = [
        Customer::class => 'customer_id',
    ];
}

$customer = Customer::find(1);

// First access: computes via SQL, caches the result
$customer->balance;    // 1250.75

// Second access: instant cache hit, no query
$customer->balance;    // 1250.75

// Create a new entry — cache is automatically invalidated
CustomerLedgerEntry::create([
    'customer_id' => 1,
    'amount' => 500,
]);

// Next access: recalculates transparently
$customer->balance;    // 1750.75

#[FlowField(method: 'sum', relation: 'entries', column: 'amount')]
protected function balance(): Attribute { ... }

#[FlowField(method: 'count', relation: 'entries')]
protected function entryCount(): Attribute { ... }

#[FlowField(method: 'avg', relation: 'entries', column: 'amount')]
protected function averageAmount(): Attribute { ... }

#[FlowField(method: 'min', relation: 'entries', column: 'amount')]
protected function minAmount(): Attribute { ... }

#[FlowField(method: 'max', relation: 'entries', column: 'amount')]
protected function maxAmount(): Attribute { ... }

#[FlowField(method: 'exists', relation: 'entries')]
protected function hasEntries(): Attribute { ... }

#[FlowField(method: 'sum', relation: 'entries', column: 'amount', where: ['type' => 'invoice'])]
protected function totalInvoiced(): Attribute { ... }

#[FlowField(method: 'sum', relation: 'entries', column: 'amount', where: ['type' => 'credit'])]
protected function totalCredits(): Attribute { ... }

// Array values use whereIn
#[FlowField(method: 'count', relation: 'entries', where: ['status' => ['pending', 'processing']])]
protected function openEntryCount(): Attribute { ... }

class OrderLine extends Model
{
    use InvalidatesFlowFields;

    // Map parent models to their foreign key on this table
    protected array $flowFieldTargets = [
        Order::class => 'order_id',
        Customer::class => 'customer_id',
    ];
}

// Recalculate specific fields
$customer->calcFlowFields('balance', 'entry_count');

// Recalculate all FlowFields
$customer->calcFlowFields();

// Flush specific fields
$customer->flushFlowFields('balance');

// Flush all FlowFields for this record
$customer->flushFlowFields();

// Compute specific fields for all results
$customers = Customer::withFlowFields('balance', 'entry_count')->get();

// Compute all FlowFields
$customers = Customer::withFlowFields()->get();

// Highest balance first
$customers = Customer::orderByFlowField('balance', 'desc')->get();

// Combine with other conditions
$customers = Customer::where('active', true)
    ->orderByFlowField('entry_count', 'desc')
    ->paginate(25);

$definitions = $customer->getFlowFieldDefinitions();
// Returns: ['balance' => FlowFieldDefinition, 'entry_count' => FlowFieldDefinition, ...]

'cache' => [
    'store' => env('FLOWFIELD_CACHE_STORE', null),
],

'cache' => [
    'ttl' => null,  // Forever — invalidation is event-driven
],

'cache' => [
    'prefix' => 'flowfield',
],

'auto_warm' => false,  // Set to true for always-hot caches

'tag_based' => true,

class Order extends Model
{
    use HasFlowFields;

    public function lines() { return $this->hasMany(OrderLine::class); }

    #[FlowField(method: 'sum', relation: 'lines', column: 'line_total')]
    protected function total(): Attribute
    {
        return Attribute::make(get: fn () => null);
    }

    #[FlowField(method: 'count', relation: 'lines')]
    protected function lineCount(): Attribute
    {
        return Attribute::make(get: fn () => null);
    }
}

class Tenant extends Model
{
    use HasFlowFields;

    public function users() { return $this->hasMany(User::class); }
    public function invoices() { return $this->hasMany(Invoice::class); }

    #[FlowField(method: 'count', relation: 'users')]
    protected function userCount(): Attribute
    {
        return Attribute::make(get: fn () => null);
    }

    #[FlowField(method: 'sum', relation: 'invoices', column: 'amount', where: ['status' => 'paid'])]
    protected function totalRevenue(): Attribute
    {
        return Attribute::make(get: fn () => null);
    }

    #[FlowField(method: 'exists', relation: 'invoices', where: ['status' => 'overdue'])]
    protected function hasOverdueInvoices(): Attribute
    {
        return Attribute::make(get: fn () => null);
    }
}

class Product extends Model
{
    use HasFlowFields;

    public function stockMovements() { return $this->hasMany(StockMovement::class); }

    #[FlowField(method: 'sum', relation: 'stockMovements', column: 'quantity')]
    protected function inventoryQuantity(): Attribute
    {
        return Attribute::make(get: fn () => null);
    }
}
bash
php artisan vendor:publish --tag=flowfield-config