Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 5.4 Relations are not loading inside Model boot method

I have a model named 'Poll'. Inside Poll model I defined a boot method like follows:

public static function boot()
{
    parent::boot();

    self::created(function($model){
       // dd($model);
       $speakers = $model->speakers()->get();
       // dd($speakers);

       // What I want to do here is: create poll options relation from speakers as follows
       // $poll->poll_options()->create([
       //     'option' => $speaker->name,
       // ]);
    }
}

I am adding the speakers relation and it is working perfect.

But inside this boot method, inside self::created if I tried to get the speakers relation, it is always empty (dd($speakers) line). Is it because of the boot method runs just after the model is saved into DB and the relations not at all saved?

I am getting newly created model in the line: dd($model) mentioned in the code.

UPDATE

I tried with events also. My Poll Model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Backpack\CRUD\CrudTrait;
use Cookie;
use App\Events\PollCreated;

class Poll extends Model
{
  ........
  protected $events = [
        'created' => PollCreated::class,
    ];
  .......

  public function speakers()
  {
    return $this->belongsToMany('App\Models\Speaker','poll_speaker','poll_id','speaker_id');
  }
}

app/Events/PollCreated.php:

namespace App\Events;

use App\Models\Poll;
use Illuminate\Queue\SerializesModels;

class PollCreated
{
  use SerializesModels;

  public $poll;

  /**
   * Create a new event instance.
   *
   * @param  Poll  $poll
   * @return void
   */
  public function __construct(Poll $poll)
  {
      // $this->poll = $poll;
      $event = $poll->event()->first();
      // dd($event);
      // dd($poll->speakers()->get());
      // dd($poll->load('speakers'));
  }
}

Here also I am not getting speakers, in the line: dd($poll->speakers()->get());

my Speaker model:

    <?php

    namespace App\Models;

    use Illuminate\Database\Eloquent\Model;
    use Backpack\CRUD\CrudTrait;

    class Speaker extends Model
    {
    use CrudTrait;
    ……..

        public function polls()
        {
            return $this->belongsToMany('App\Models\Poll');
        }
    ……..
    }
like image 281
Abhi Avatar asked Oct 17 '22 03:10

Abhi


1 Answers

The problem is with timing as models must always be created before they can be set in a many-to-many relationship. So there is no possible way that in a many-to-many relationship during the created event the relationship is already set as the created events are always raised before the relationships.

Anyone looking for a solution can probably experiment with the chelout/laravel-relationship-events package as this adds relationship events to models.

To be sure, I tested this out with a simple application of users and computers.

User.php

class User extends Model
{
    use HasBelongsToManyEvents;

    public static function boot() {
        parent::boot();

        self::created(function($model){
           Log::info('user::created');
        });

        static::belongsToManyAttaching(function ($relation, $parent, $ids) {
            $ids = implode(' & ', $ids);
            Log::info("Attaching {$relation} {$ids} to user.");
        });

        static::belongsToManyAttached(function ($relation, $parent, $ids) {
            $ids = implode(' & ', $ids);
            Log::info("Computers {$ids} have been attached to user.");
        });
    }

    public function computers() {
        return $this->belongsToMany(Computer::class, 'user_computers');
    }
}

Computer class is the same in reverse. And for the following code:

$user = User::create();

$user->computers()->attach([
    Computer::create()->id,
    Computer::create()->id
]);

This was the outcome:

user::created  
computer::created  
computer::created  
Attaching computers 69 & 70 to user.  
Computers 69 & 70 have been attached to user.  
like image 128
Artur K. Avatar answered Oct 20 '22 23:10

Artur K.