Hello there! Today, I want to share an interesting challenge I faced while working on a simple TV Show/Season management project using php-activerecord. I encountered a fatal error that left me scratching my head:
Fatal error: Type of App\Models\TvShow::$has_many must be array (as in class ActiveRecord\Model)
After some digging, I figured out why this happens and how to fix it. Let’s walk through my journey, see the corrected code, and then explore how you can leverage php-activerecord for creating, reading, updating, and deleting your data in a very straightforward manner.
Why the Error Occurs
I learned that the php-activerecord library expects all relationship definitions (like $has_many
, $belongs_to
, $has_one
, $has_and_belongs_to_many
) to be declared as an array of arrays. That means each relationship should be wrapped in its own array. For instance:
static $has_many = [ ['seasons'] ];
However, I initially wrote something like:
static $has_many = [ 'seasons' => [] ];
That’s when everything broke because 'seasons' => []
doesn’t match what php-activerecord expects. It’s supposed to look more like [['seasons']]
or [['seasons', 'class_name' => 'Season']]
if you need extra options like foreign keys or custom class names.
So, that’s the root cause of the fatal error. Thankfully, it’s also an easy fix.
Corrected Code
TvShow.php
<?php namespace App\Models; require 'vendor/autoload.php'; use ActiveRecord\Model; class TvShow extends Model { // Correct usage: array of arrays static $has_many = [ ['seasons'] ]; }
Season.php
<?php namespace App\Models; require 'vendor/autoload.php'; use ActiveRecord\Model; class Season extends Model { // Correct usage: array of arrays static $belongs_to = [ ['tv_show'] ]; }
Optional – Adding Relationship Options
If your seasons
table uses a column named something else (instead of the default tv_show_id
) or if you want to specify the class name, you can write:
static $has_many = [ ['seasons', 'class_name' => 'App\\Models\\Season', 'foreign_key' => 'tv_show_id'] ];
Adding Practical Functionality
Now that the relationship syntax is fixed, here’s how I actually used it in my project.
Example Usage
use App\Models\TvShow; use App\Models\Season; // 1. Create a new TV show $show = new TvShow(); $show->title = "My Awesome Show"; $show->created_at = date('Y-m-d H:i:s'); $show->save(); // 2. Create a new Season and attach it to a TV Show $season1 = new Season(); $season1->number = 1; $season1->tv_show_id = $show->id; $season1->save(); // 3. Retrieve the TV show with all its seasons $retrievedShow = TvShow::find($show->id); echo "Show Title: " . $retrievedShow->title . PHP_EOL; foreach ($retrievedShow->seasons as $season) { echo "Season #: " . $season->number . PHP_EOL; }
Here, the $show
variable is an instance of the TvShow
model. Once you create it, you can attach Season
instances to it by referencing the foreign key (tv_show_id
).
Finding and Updating Data
// Find a TvShow by primary key $tvShow = TvShow::find(1); // Update title $tvShow->title = "Updated Title"; $tvShow->save(); // Find multiple shows with conditions $shows = TvShow::find('all', [ 'conditions' => ['title LIKE ?', '%Awesome%'] ]); foreach ($shows as $s) { echo $s->title . PHP_EOL; }
This is handy if you want to refine your searches (for example, searching by partial titles).
Deleting Records
$season = Season::find(10); $season->delete();
You can easily remove records from your database once you have the object
Tips and Best Practices
Use Namespaced Classes
I placed mine under App\Models
. Make sure your Composer autoload is configured properly for these namespaces.
Migrations / DB Setup
Ensure your database has the right tables and columns:
tv_shows
might have columns likeid
,title
,created_at
.seasons
might haveid
,number
,tv_show_id
, etc.
Relationship Options
If your primary or foreign keys differ from id
and tv_show_id
, specify them in the relationship arrays. Example:
static $has_many = [ ['seasons', 'foreign_key' => 'my_custom_foreign_key'] ];
Validation
php-activerecord also supports built-in validations, for example:
static $validates_presence_of = [ ['title', 'message' => 'Title cannot be blank'] ];
Timestamps
If you have created_at
and updated_at
columns in your tables, php-activerecord can automatically populate them when you enable:
static $timestamps = true;
Final Thoughts
The error stemmed from a small, yet critical detail in relationship definitions. Once fixed, php-activerecord
becomes a smooth and intuitive ORM for your projects. Leverage validations, timestamps, and proper namespace setups for a clean codebase. Add migrations or schema definitions to safeguard data integrity.