ManyToMany Repeater: Call to a member function subscriptionProducts() on null

I have followed this guide: https://filamentphp.com/docs/3.x/forms/fields/repeater#integrating-with-a-belongstomany-eloquent-relationship but unfortunately no luck. My models: subscription: - id - name productSubscription - id - product_id - subscription_id - price - quantity product: - id - name - tax - default_price
3 Replies
Proculair
Proculair6mo ago
<?php

namespace App\Models;

use App\Enums\SubscriptionPeriod;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Subscription extends Model
{
use HasFactory;
use HasUlids;

protected $fillable = [
'name',
'notes',
'period',
'starts_on',
'ends_on',
];

protected $casts = [
'period' => SubscriptionPeriod::class,
'starts_on' => 'date',
'ends_on' => 'date',
];

protected $with = [
'products',
];

public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class);
}

public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class)
->using(ProductSubscription::class)
->withPivot(['price', 'quantity']);
}

public function subscriptionProducts(): HasMany
{
return $this->hasMany(ProductSubscription::class);
}
}
<?php

namespace App\Models;

use App\Enums\SubscriptionPeriod;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Subscription extends Model
{
use HasFactory;
use HasUlids;

protected $fillable = [
'name',
'notes',
'period',
'starts_on',
'ends_on',
];

protected $casts = [
'period' => SubscriptionPeriod::class,
'starts_on' => 'date',
'ends_on' => 'date',
];

protected $with = [
'products',
];

public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class);
}

public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class)
->using(ProductSubscription::class)
->withPivot(['price', 'quantity']);
}

public function subscriptionProducts(): HasMany
{
return $this->hasMany(ProductSubscription::class);
}
}
<?php

namespace App\Models;

use Akaunting\Money\Money;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;

class ProductSubscription extends Pivot
{
protected $fillable = [
'product_id',
'price',
'quantity',
];

public function product(): BelongsTo
{
return $this->belongsTo(Product::class);
}

public function subscription(): BelongsTo
{
return $this->belongsTo(Subscription::class);
}
}
<?php

namespace App\Models;

use Akaunting\Money\Money;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;

class ProductSubscription extends Pivot
{
protected $fillable = [
'product_id',
'price',
'quantity',
];

public function product(): BelongsTo
{
return $this->belongsTo(Product::class);
}

public function subscription(): BelongsTo
{
return $this->belongsTo(Subscription::class);
}
}
<?php

namespace App\Models;

use Akaunting\Money\Money;
use App\Enums\ProductTax;
use App\Enums\ProductType;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Product extends Model
{
use HasFactory;
use HasUlids;

protected $fillable = [
'name',
'type',
'tax',
'price',
];

protected $casts = [
'type' => ProductType::class,
'tax' => ProductTax::class,
];

public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}

public function subscriptions(): BelongsToMany
{
return $this->belongsToMany(Subscription::class)
->using(ProductSubscription::class);
}
}
<?php

namespace App\Models;

use Akaunting\Money\Money;
use App\Enums\ProductTax;
use App\Enums\ProductType;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Product extends Model
{
use HasFactory;
use HasUlids;

protected $fillable = [
'name',
'type',
'tax',
'price',
];

protected $casts = [
'type' => ProductType::class,
'tax' => ProductTax::class,
];

public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}

public function subscriptions(): BelongsToMany
{
return $this->belongsToMany(Subscription::class)
->using(ProductSubscription::class);
}
}
<?php

namespace App\Filament\AppPanel\Resources\CustomerResource\Pages;

use App\Filament\AppPanel\Resources\CustomerResource;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
use Filament\Resources\Pages\ManageRelatedRecords;

class ManageCustomerSubscriptions extends ManageRelatedRecords
{
protected static string $resource = CustomerResource::class;

protected static string $relationship = 'subscriptions';

protected static ?string $navigationIcon = 'heroicon-o-document-duplicate';

protected static ?string $navigationLabel = 'Abonnementen';

protected static ?string $breadcrumb = 'Abonnementen';

public function getTitle(): string
{
return $this->record->name;
}

public function form(Form $form): Form
{
return $form
->schema([
Repeater::make('subscriptionProducts')
->relationship()
->schema([
Select::make('product_id')
->relationship('product', 'name')
->required(),
]),
]);
}
//...
<?php

namespace App\Filament\AppPanel\Resources\CustomerResource\Pages;

use App\Filament\AppPanel\Resources\CustomerResource;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
use Filament\Resources\Pages\ManageRelatedRecords;

class ManageCustomerSubscriptions extends ManageRelatedRecords
{
protected static string $resource = CustomerResource::class;

protected static string $relationship = 'subscriptions';

protected static ?string $navigationIcon = 'heroicon-o-document-duplicate';

protected static ?string $navigationLabel = 'Abonnementen';

protected static ?string $breadcrumb = 'Abonnementen';

public function getTitle(): string
{
return $this->record->name;
}

public function form(Form $form): Form
{
return $form
->schema([
Repeater::make('subscriptionProducts')
->relationship()
->schema([
Select::make('product_id')
->relationship('product', 'name')
->required(),
]),
]);
}
//...
Without the select the page modal loads. With it Call to a member function subscriptionProducts() on null I thought it might have something to do with ulids, so I temporarily used normal ids everywhere in my app. This did not change the result
Abel Cobreros
Abel Cobreros5mo ago
Hey did you manage to find a solution to this? I'm getting the same error
Proculair
Proculair5mo ago
No I did not, ended up using a relation manager instead :/