cvsouth/eloquent-inheritance

Eager loading not working

Closed this issue · 2 comments

This is a minimal example that illustrates the issue:
suppose you have a One To Many relationship between users and posts

Migrations

Schema::create('users', function (Blueprint $table) {
    $table->bigIncrements('id')->unsigned();
    $table->bigInteger('base_id')->unsigned();
    $table->string('name');
    $table->timestamps();
});

Schema::create('super_users', function (Blueprint $table) {
    $table->bigIncrements('id')->unsigned();
    $table->bigInteger('base_id')->unsigned();
    $table->string('super_name');
    $table->timestamps();
});

Schema::create('posts', function (Blueprint $table) {
    $table->bigIncrements('id')->unsigned();
    $table->text('title')->nullable();
    $table->integer('user_id')->unsigned();
    $table->timestamps();
});

Models

class User extends InheritableModel
{
    use HasFactory;

    public $table = "users";

    protected  $guard =[
        'id'
    ];

    public function posts()
    {
        return $this->hasMany(Post::class, 'user_id');
    }
    // factory method
}

class SuperUser extends User
{
    use HasFactory;

    public $table = "super_users";

    protected  $guard =[
        'id'
    ];

   // skipping factory method to save space
}

class Post extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Create some SuperUsers and associated posts:

SuperUser::factory()->count(10)->create()->each(function ($user) {
      $posts = Post::factory()->count(rand(1, 5))->make();
      $user->posts()->saveMany($posts);
});

The issue is that because the child class 'SuperUser' was used to create the record, the following code won't load the post data, though, all the users are loaded correctly.

$res = User::with('posts')->get();

But in some situation in my code I need to retrieve all user independently with theirs associated posts

  0 => array:6 [▼
    "id" => 1
    "base_id" => 21
    "super_name" => "SuperUser"
    "created_at" => null
    "updated_at" => null
    "name" => "set from super user"
  ]

To get the post loaded i'm obliged to load the data with the same class that is used in my factory.

$res = SuperUser::with('posts')->get(); // Notice the SuperUser instead of User
 0 => array:7 [▼
    "id" => 1
    "base_id" => 21
    "super_name" => "SuperUser"
    "created_at" => null
    "updated_at" => null
    "name" => "set from super user"
    "posts" => array:5 [▼
      0 => array:5 [▶]
      1 => array:5 [▶]
      2 => array:5 [▶]
      3 => array:5 [▶]
      4 => array:5 [▶]
    ]
  ]

Question: How can I load all data with all the associated relations? I need to list them all users and super users
Thanks

Apologies for the slow reply. I've added some code recently to handle relations. I'll set up a test project with your specific requirement and double check it is working as expected but in theory this should work since version 1.0.15.

@Oliamster I've recreated the scenario using the latest release 1.0.20 and the relations are loading fine with both:

$res = User::with('posts')->get();
$res = SuperUser::with('posts')->get();

Which should be the case since 1.0.15. If you're debugging you'll find all the relations in the $relations property of the top object (in this case SuperUser), as opposed to $attributes which are distributed up the hierarchy.

Let me know if there's any problems.