0

I have a Client model, the client belongs to many client addresses. on the controller the show method passes in the Client but if I try and access the addresses method it throws the below error.

Invalid argument supplied for foreach() (View: /var/www/resources/views/clients/show.blade.php)

show.blade.php

@extends('layouts.app')
@section('content')
<section class="content-header">
    <h1 class="pull-left">Client {{ $client->client_name }}</h1>
</section>
<div class="content">
    <div class="clearfix"></div>

    @include('flash::message')

    <div class="clearfix"></div>
    <div class="box box-primary">
        <div class="box-body">

            @foreach ($client->addresses as $address)
               {{ $address->address_line1 }}
            @endforeach
        </div>
    </div>
    <div class="text-center">

    </div>
</div>
@endsection

Controller

/**
 * Display the specified resource.
 *
 * @param  \App\Client  $client
 * @return \Illuminate\Http\Response
 */
public function show(Client $client)
{
    //
    return view('clients.show')->with('client', $client);
}

Client Model

class Client extends Model
{
    //
    use SoftDeletes;

    protected $table = 'clients';
    //protected $primaryKey  = 'id';

    const CREATED_AT = 'created_at';
    const UPDATED_AT = 'updated_at';


    protected $dates = ['deleted_at'];


    public $fillable = [
        'client_ref',
        'client_name',
        'is_active'
    ];

    /**
     * The attributes that should be casted to native types.
     *
     * @var array
     */
    protected $casts = [
        'id' => 'integer',
        'client_ref' => 'string',
        'client_name' => 'string',
        'is_active' => 'string',
        'created_at' => 'date',
        'updated_at' => 'date'
    ];

    /**
     * Validation rules
     *
     * @var array
     */
    public static $rules = [

    ];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     **/
    public function addresses()
    {
        return $this->hasMany('ClientsAddresses');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function history()
    {
        return $this->hasMany('ClientsHistory');
    }
}

ClientsAddresses Model

class ClientsAddresses extends Model
{
    //
    protected $table = 'clients_addresses';

    const CREATED_AT = 'created_at';
    const UPDATED_AT = 'updated_at';

    public $fillable = [
        'client_id', 'address_type', 'is_active', 'address_line1', 'address_line2', 'address_line3',
        'city', 'country', 'postcode'
    ];

    public function Client(){
        return $this->hasOne('App\Models\Client');
    }
}

Clients Migration

Schema::create('clients', function (Blueprint $table) {
        $table->increments('id');
        $table->string("client_ref");
        $table->string('client_name');
        $table->enum('is_active', ['Y', 'N'])->default('Y');
        $table->timestamps();
        $table->softDeletes();
    });

Clients Addresses Migration

Schema::create('clients_addresses', function (Blueprint $table) {
    $table->increments('id');
    $table->unsignedInteger('client_id')->comments('id from the clients table');
    $table->enum('address_type', ['Billing', 'Shipping'])->default('Billing');
    $table->enum('is_active', ['Y', 'N'])->default('Y');
    $table->string('address_line1');
    $table->string('address_line2')->nullable();
    $table->string('address_line3')->nullable();
    $table->string('city');
    $table->string('country')->default('UK');
    $table->string('postcode');
    $table->timestamps();
    $table->index(['address_type', 'is_active']);
 });

Foreign Key Migration

Schema::table('clients_addresses', function (Blueprint $table) {
    //
    if (Schema::hasColumn('clients_addresses', 'client_id')) {
        $table->foreign('client_id')->references('id')->on('clients');
    }
});
Neo
  • 2,305
  • 4
  • 36
  • 70

2 Answers2

1

I think you have to write full path in :

public function addresses()
{
    return $this->hasMany('ClientsAddresses');
}


public function history()
{
    return $this->hasMany('ClientsHistory');
}

try like:

return $this->hasMany('App\ClientsHistory');
 return $this->hasMany('App\ClientsAddresses');
Ghyath Darwish
  • 2,614
  • 4
  • 15
  • 31
1

You have to change the parameter type hint that Laravel uses for route model binding:

/**
 * Display the specified resource.
 *
 * @param  \App\Models\Client  $client
 * @return \Illuminate\Http\Response
 */
public function show(\App\Models\Client $client)
{
    return view('clients.show')->with('client', $client);
}

As Ghyath Darwish points out, you also have to specify the whole class name in your relationships.
Or use YourModel::class if both models share the same namespace.

Jonas Staudenmeir
  • 24,815
  • 6
  • 63
  • 109