Return queried model in Eloquent attribute

2019-08-26 20:14发布

问题:

I'm using Laravel's eloquent ORM, and I was hoping to be able to return a queried laravel model as an attribute, or more ideally as an eloquent relation. This is what I'm trying to do:

class CalendarEvent extends Model
{
    protected $appends = array('conflicts');

    public function getConflictsAttribute () {
        $conflicts =  CalendarEvent::where('calendar_event_type','=',$this->calendar_event_type)
                      ->where('start','<',$this->end)
                      ->where('end','>',$this->start)
                      ->get();   

        return $conflicts;
    }
}

This is an attempt to get over-lapping calendar events, which would be the conflicting events, returned as an object against each event.

This would then mean any query run would return the conflicts :

$event = CalendarEvent::where('id','=',123)->first()->toJson();
$event; // JSON object should contain conflicting events

This results in a non-laravel 500 error, and a blank page. The storage/logs/laravel is not appended to. My /var/log/site-error.log has this appended during the request:

PHP message: PHP 324. Illuminate\Database\Eloquent\Model->attributesToArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2454 PHP message: PHP 325. Illuminate\Database\Eloquent\Model->mutateAttributeForArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2518 PHP message: PHP 326. Illuminate\Support\Collection->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2764 PHP message: PHP 327. array_map() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 328. Illuminate\Support\Collection->Illuminate\Support{closure}() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 329. Illuminate\Database\Eloquent\Model->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1102 PHP message: PHP 330. Illuminate\Database\Eloquent\Model->attributesToArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2454 PHP message: PHP 331. Illuminate\Database\Eloquent\Model->mutateAttributeForArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2518 PHP message: PHP 332. Illuminate\Support\Collection->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2764 PHP message: PHP 333. array_map() /home/vagrant/silverback/ 2016/12/04 14:21:16 [error] 792#0: *42880 FastCGI sent in stderr: "home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 370. Illuminate\Support\Collection->Illuminate\Support{closure}() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 371. Illuminate\Database\Eloquent\Model->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1102 PHP message: PHP 372. Illuminate\Database\Eloquent\Model->attributesToArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2454 PHP message: PHP 373. Illuminate\Database\Eloquent\Model->mutateAttributeForArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2518 PHP message: PHP 374. Illuminate\Support\Collection->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2764 PHP message: PHP 375. array_map() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 376. Illuminate\Support\Collection->Illuminate\Support{closure}() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 377. Illuminate\Database\Eloquent\Model->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1102 PHP message: PHP 378. Illuminate\Database\Eloquent\Model->attributesToArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2454 PHP message: PHP 379. Illuminate\Database\Eloquent\Model->mutateAttributeForArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2518 PHP message: PHP 380. Illuminate\Support\Collection->toArray() /home/vagrant/silverback/httpdocs/vendor/larav 2016/12/04 14:21:16 [error] 792#0: *42880 FastCGI sent in stderr: "ck/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2764 PHP message: PHP 417. array_map() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 418. Illuminate\Support\Collection->Illuminate\Support{closure}() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 419. Illuminate\Database\Eloquent\Model->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1102 PHP message: PHP 420. Illuminate\Database\Eloquent\Model->attributesToArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2454 PHP message: PHP 421. Illuminate\Database\Eloquent\Model->mutateAttributeForArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2518 PHP message: PHP 422. Illuminate\Support\Collection->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2764 PHP message: PHP 423. array_map() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 424. Illuminate\Support\Collection->Illuminate\Support{closure}() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 425. Illuminate\Database\Eloquent\Model->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1102 PHP message: PHP 426. Illuminate\Database\Eloquent\Model->attributesToArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2454 PHP message: PHP 427. Illuminate\Database\Eloquent\Model->mutateAttributeForArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Mode 2016/12/04 14:21:16 [error] 792#0: *42880 FastCGI sent in stderr: "e/Database/Eloquent/Model.php:2518 PHP message: PHP 464. Illuminate\Support\Collection->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2764 PHP message: PHP 465. array_map() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 466. Illuminate\Support\Collection->Illuminate\Support{closure}() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 467. Illuminate\Database\Eloquent\Model->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1102 PHP message: PHP 468. Illuminate\Database\Eloquent\Model->attributesToArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2454 PHP message: PHP 469. Illuminate\Database\Eloquent\Model->mutateAttributeForArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2518 PHP message: PHP 470. Illuminate\Support\Collection->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2764 PHP message: PHP 471. array_map() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 472. Illuminate\Support\Collection->Illuminate\Support{closure}() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1103 PHP message: PHP 473. Illuminate\Database\Eloquent\Model->toArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Support/Collection.php:1102 PHP message: PHP 474. Illuminate\Database\Eloquent\Model->attributesToArray() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2454 PHP message: PHP 475. Illuminate\Database\Eloquent\Model->mu 2016/12/04 14:21:16 [error] 792#0: *42880 FastCGI sent in stderr: "ry\Grammars\MySqlGrammar->wrapValue() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Grammar.php:79 PHP message: PHP 511. Illuminate\Database\Query\Grammars\MySqlGrammar->isJsonSelector() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php:225 PHP message: PHP 512. Illuminate\Support\Str::contains() /home/vagrant/silverback/httpdocs/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php:255" while reading response header from upstream, client: 192.168.42.1, server: silverback.dev, request: "GET /test HTTP/1.1", upstream: "fastcgi://unix:/var/run/php5-fpm.sock:", host: "silverback.dev"

UPDATE: I've decided this just isn't possible using Eloquent ORM. What I'm essentially trying to do is a Mysql like this, attaching as a relationship:

select * from calendar_events as calendar_events_2 where calendar_events_2.start < calendar_events_1.end AND calendar_events_2.end > calendar_events_1.start

Instead I've relunctently opted for a foreach loop to attach the data after it has been fetched. I believe this is my only option.

foreach ($shoot_timeline_data as $shoot) {
    foreach ($shoot->booking_cases as $booking_case) {
        $booking_case->booking->conflicts = CalendarEvent::find_clashes(
            $booking_case->booking->calendar_event_type, 
            $booking_case->booking->start, 
            $booking_case->booking->end,
            [$booking_case->booking->id] // excludes this ID via 'whereNotIn'
        );
    }
}

回答1:

The error seems to be arising out of appended attribute, where you are trying to get other model instances in an array. A different approach could be to define a relation on self like

class CalendarEvent extends Model{
    public function conflicts()
    { 
        return  $this->hasMany(CalendarEvent::class)
                ->where('calender_event_type','=', $this->calendar_event_type);
    }
}  

Then you can try to query as

$event = CalendarEvent::where('id','=',123)->with('conflicts')->first()->toJson();  

Haven't tested, but try to see if it works.

EDIT

Try using parameters with lazy loading

$event = CalendarEvent::where('id', '=', 123)->first();
or
$event = CalendarEvent::findOrFail(123);  //it will find the record by given primary key - 123 or fail i.e. throw 'MODELNOTFOUNDEXCEPTION'

$start = $event->start;
$end = $event->end;
$event->load('conflicts', function($query) use ($start, $end){
          $query->where('start', '<', $start)
                ->where('end', '>', $end)
        })->get();


回答2:

You need to return it

class CalendarEvent extends Model
{
    protected $appends = array('conflicts');

    public function getConflictsAttribute () 
    {
        return CalendarEvent::where('calendar_event_type','=',$this->calendar_event_type)
                      ->where('start','<',$this->end)
                      ->where('end','>',$this->start)
                      ->get();   
    }
}