dimanche 22 avril 2018

Laravel 5.6, relationship path is returning array instead of object

Longtime googler, first time asker here. Hi, folks. I am debugging and updating my app after updating it from Laravel 5.1.10 to 5.6 and this bug is proving hard to google.

Exploring my error message “Trying to get property of non-object” I think what is happening is that the nested relationship path that used to work just fine to give me the object, is now instead giving me an array of its attributes.

More code below, but here is the snippet from my view:

@section('content')
<h2>
<?php // Header: project number and title ?>
@if ($bookingDefault->project->courseNumber)
    : 
@endif

This results in error:

Trying to get property 'courseNumber' of non-object 

It’s not returning a null; the data is there and it works perfectly fine if I access the project as an array thus:

@section('content')
<h2>
<?php // Header: project number and title ?>
@if ($bookingDefault->project['courseNumber'])
    : 
@endif

So I know that the relationships are defined okay because it is finding the project. It’s just not giving a proper object to the view anymore. I could change a large number of views to access attributes as an array instead, but that is a lot of code to comb through and change, and doesn’t give me access to the object’s methods. I would rather fix why I am getting an array instead of the object I was getting before.

CODE THAT MAY BE RELEVANT:

from app/Http/Kernel.php (partial) - I checked that SubstituteBindings::class is there.

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],
];

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
protected $routeMiddleware = [
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];

from routes/web.php (partial) - all my old Route::model and Route::bind are still there. I wasn’t sure if I was supposed to take them out or put them somewhere else but fiddling with it didn’t change anything. I tried moving them to RouteServiceProvider’s boot() function but that didn’t change anything so I put them back into web.php.

Route::model('bookingdefaults', 'BookingDefault');
Route::model('bookings',        'Booking');
Route::model('people',          'User');
Route::model('projects',        'Project');

Route::bind('bookingdefaults',  function($value, $route) {return App\BookingDefault::where('id', $value)->first();});
Route::bind('bookings',         function($value, $route) {return App\Booking::where('id', $value)->first();});
Route::bind('people',           function($value, $route) {return App\User::where('id', $value)->first();});
Route::bind('projects',         function($value, $route) {return App\Project::where('id', $value)->first();});

In the models - again, not the complete code which is long:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class BookingDefault extends Model
{
    protected $guarded = [];

// RELATIONSHIPS

    // always belongs to a certain project
    public function project()
    {
        return $this->belongsTo('App\Project');
    }
    // always happens a certain place
    public function location()
    {
        return $this->belongsTo('App\Location');
    }
    // many bookings could be made from this default
    public function bookings()
    {
        return $this->hasMany('App\Booking');
    }
    // each booking default will suggest several roles that might be filled in a booking
    public function bookingDefaultRoleAssignments()
    {
        return $this->hasMany('App\BookingDefaultRoleAssignment');
    }

    // somtimes it is defining a default of a certain type, but if this is a 
    // customized default then it may not belong to a bookingType
    public function bookingType()
    {
        return $this->belongsTo('App\BookingType');
    }
}

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Mail;
use App\Booking;

class Project extends Model
{
     protected $guarded = [];

// RELATIONSHIPS
    public function bookings()
    {
        return $this->hasMany('App\Booking');
    }
    // a project can have defaults for several types of booking
    public function bookingDefaults()
    {
        return $this->hasMany('App\BookingDefault');
    }
    // there will be many assignments of users to this project in various roles
    public function projectRoleAssignments()
    {
        return $this->hasMany('App\ProjectRoleAssignment');
    }
    public function projectType()
    {
        return $this->belongsTo('App\ProjectType');
    }
}

from BookingDefaultsController.php (partial - actual controller is over 1000 lines)

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;

use Illuminate\Database\Eloquent\Collection;
use App\User;
use App\Booking;
use App\BookingDefault;
use App\BookingDefaultRoleAssignment;
use App\BookingRoleAssignment;
use App\BookingRole;
use App\BookingType;
use App\Location;
use App\Project;
use App\Qualification;
use Illuminate\Support\Facades\DB;

use Input;
use Redirect;
use Mail;

class BookingDefaultsController extends Controller
{
     /**
     * Show the form for editing the specified resource.
     */
    public function edit(BookingDefault $bookingDefault)
    {
        // We'll need all the options for form dropdowns
        $locations = Location::where('status', 'active')->orderby('location_name')->get();
        $bookingTypes = BookingType::all();
        $bookingRoles = BookingRole::all();
        $qualifications = Qualification::all();

        return view('bookingdefaults.edit', 
            compact('bookingDefault', 'locations', 'bookingTypes', 'bookingRoles', 'qualifications'));
    }

}

And finally the view, from /resources/views/bookingdefaults/edit.blade.php

@extends('layout')

@section('title')
    Staffstuff Edit Booking Default
@stop
@section('php')
   
@stop

@section('navtag')
   <div id="projpage">
@stop

@section('javascript')

@stop

@section('content')
    <h2>
    <?php // Header: project number and title ?>
    @if ($bookingDefault->project->courseNumber)
        : 
    @endif
    @if ($bookingDefault->project->shortTitle)  
        @elseif ($bookingDefault->project->title) 
    @endif
    <br />Booking Default:
    </h2>
    <?php // Form to edit the basic booking info, time, place ?>
    {!! Form::model($bookingDefault, ['method' => 'PATCH', 'route' => ['bookingdefaults.update', $bookingDefault->id]]) !!}
        {!! Form::hidden('id', $bookingDefault->id) !!}
        {!! Form::hidden('project_id', $bookingDefault->project_id) !!}

        @include('/partials/bookingdefaultform', ['submit_text' => 'Update Default'])

        <div class="form-group">
            {!! Form::label('update_existing', 'Update existing bookings (see below): ') !!}
            {!! Form::checkbox('update_existing', 'value', TRUE) !!}
            <br />Note that NOT updating existing bookings will decouple them from this default and they will need to be updated individually.
        </div>

    {!! Form::close() !!}
    <p>
        <a href="">DONE EDITING</a>
    </p>

    @stop

The exact error:

ErrorException (E_ERROR)
Trying to get property 'courseNumber' of non-object (View: /Users/redacted/Sites/testproject032418/resources/views/bookingdefaults/edit.blade.php)



from Newest questions tagged laravel-5 - Stack Overflow https://ift.tt/2F8hnqN
via IFTTT

Aucun commentaire:

Enregistrer un commentaire