Laravel 5.6,关系路径返回数组而不是对象

时间:2018-04-22 18:37:10

标签: php laravel laravel-5

长期的Google员工,这里的第一次提问者。嗨伙计。 从Laravel 5.1.10到5.6更新后,我正在调试和更新我的应用程序 这个bug很难谷歌。

探索我的错误消息“试图获取非对象的属性”我认为发生的事情是,过去工作得很好的嵌套关系路径给我的对象,现在改为给我一个属性数组

下面有更多代码,但这是我视图中的代码段:

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

这会导致错误:

Trying to get property 'courseNumber' of non-object 

它没有返回null;数据就在那里,如果我以一个数组的形式访问项目,它就可以正常工作:

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

所以我知道关系定义得好,因为它正在寻找项目。它不再给视图提供适当的对象了。 我可以改变大量的视图来代替作为数组访问属性,但这需要很多代码来梳理和更改,并且不允许我访问对象的方法。我宁愿修复为什么我得到一个数组而不是我以前得到的对象。

可能相关的代码:

来自app / Http / Kernel.php(部分) - 我检查了SubstituteBindings :: class是否存在。

/**
 * 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,
];
来自routes / web.php(部分)的

- 所有旧的Route :: model和Route :: bind仍然存在。我不确定我是应该将它们拿出来还是把它们放在其他地方,但摆弄它并没有改变任何东西。我尝试将它们移动到RouteServiceProvider的boot()函数,但这并没有改变任何东西,所以我把它们放回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();});

在模型中 - 再次,不是完整的代码:

<?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');
    }
}
来自BookingDefaultsController.php的

(部分 - 实际控制器超过1000行)

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'));
    }

}

最后来自/resources/views/bookingdefaults/edit.blade.php的观点

@extends('layout')

@section('title')
    Staffstuff Edit Booking Default
@stop
@section('php')
   {{ $user = Auth::user() }}
@stop

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

@section('javascript')

@stop

@section('content')
    <h2>
    <?php // Header: project number and title ?>
    @if ($bookingDefault->project->courseNumber)
        {{ $bookingDefault->project->courseNumber }}: 
    @endif
    @if ($bookingDefault->project->shortTitle) {{ $bookingDefault->project->shortTitle }} 
        @elseif ($bookingDefault->project->title) {{ $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="{{ route('bookingdefaults.show', $bookingDefault) }}">DONE EDITING</a>
    </p>

    @stop

确切错误:

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

1 个答案:

答案 0 :(得分:0)

这应该有效:

RouteServiceProvider(也可能在routes中工作)从复数更改为单数并将完整命名空间添加到第二个参数:

Route::model('bookingdefault', App\BookingDefault::class);
// or: Route::model('bookingdefault', 'App\BookingDefault');

其余的都很好。

您可能也需要为其他模型执行此操作。

修改

这正是我在测试项目上尝试过的。 GrandChild只是我设置的一些随机模型:

RouteServiceProvider:

public function boot()
{
    parent::boot();
    Route::model('grandchild', \App\GrandChild::class);
}

路线:

Route::resource('grandchildren', 'GrandChildController');

GrandChildController:

public function show(GrandChild $canBeWhatever)
{
    return $canBeWhatever;
}

它有效:

Result