Troubleshooting

Common Issues

"Model application instance has not been set"

Error: RuntimeException: Model application instance has not been set. Ensure ModelServiceProvider is registered.

Cause: You're using a model before the ModelServiceProvider has been registered and booted.

Fix: Register the provider in your plugin bootstrap:

use WPZylos\Framework\Model\ModelServiceProvider;

$app->register(new ModelServiceProvider());

Make sure this runs before any model operations.


Mass Assignment Not Working

Symptom: Attributes are not being set when using Model::create() or $model->fill().

Cause: The attribute is not listed in $fillable or is listed in $guarded.

Fix: Add the attribute to $fillable:

class User extends Model
{
    protected array $fillable = ['name', 'email', 'role']; // Add missing attribute
}

Or use forceFill() to bypass protection:

$user->forceFill(['is_admin' => true]);

Attribute Casting Returns Wrong Type

Symptom: An attribute returns a string instead of the expected type.

Cause: The $casts array doesn't include the attribute.

Fix: Define the cast:

protected array $casts = [
    'age'      => 'integer',
    'is_active' => 'bool',
    'price'    => 'float',
];

Null Casting

Symptom: A cast attribute returns null instead of the expected type.

Cause: Casting is intentionally skipped for null values. If the database column contains NULL, the model will return null regardless of the cast type.

Fix: Use a default value in your database schema, or handle null in your application logic:

$age = $user->age ?? 0;

Soft Deletes Not Filtering

Symptom: Soft-deleted records still appear in query results.

Cause: The SoftDeletes trait is not being used on the model.

Fix: Add the trait:

use WPZylos\Framework\Model\Concerns\SoftDeletes;

class Article extends Model
{
    use SoftDeletes;
}

Events Not Firing

Symptom: Registered model events (creating, saving, etc.) are not executing.

Cause 1: Events are registered after the model has already been booted.

Fix: Register events in the static boot() method:

protected static function boot(): void
{
    static::creating(function ($model) {
        // This will fire
    });
}

Cause 2: Event listeners from a previous test are still registered.

Fix: Flush listeners in test tearDown:

protected function tearDown(): void
{
    MyModel::flushEventListeners();
}

Relationships Return null

Symptom: Accessing a relationship returns null.

Cause 1: The foreign key value is null on the model.

Fix: Ensure the foreign key is set:

$post = Post::find(1);
var_dump($post->getAttributes()); // Check that 'user_id' has a value

Cause 2: The relationship method doesn't match the property name.

Fix: The property name must match the method name exactly:

// Method name: posts()
public function posts()
{
    return $this->hasMany(Post::class);
}

// Access via same name
$user->posts; // Good: Works
$user->post;  // Bad: Will not work

Dirty Tracking Issues

Symptom: isDirty() returns unexpected results.

Cause: The original attributes were not synced after loading.

Info: isDirty() compares current attributes against the $original snapshot. The snapshot is set:

  • When fillFromRow() is called (loading from DB)
  • When syncOriginal() is called manually
  • After a successful save() or update()

"Call to undefined method" on Scope

Symptom: BadMethodCallException: Call to undefined method Model::xxx()

Cause: The scope method is not defined with the scope prefix.

Fix: Scope methods must be prefixed with scope (camelCase):

// Define
public function scopeActive($query)   // Good: Correct
public function active($query)         // Bad: Wrong — not a scope

// Usage
Model::active(); // Calls scopeActive()

Timestamps Not Being Set

Symptom: created_at and updated_at are not populated.

Cause 1: Timestamps are disabled on the model.

Fix:

protected bool $timestamps = true; // Ensure this is true

Cause 2: Custom column names don't match your database schema.

Fix:

protected ?string $createdAtColumn = 'date_created';    // Match your schema
protected ?string $updatedAtColumn = 'date_modified';

Getting Help

If you can't find a solution here:

  1. Check the API Reference for method signatures
  2. Review the Examples for working code
  3. Open an issue on GitHub