How to get Country name for related City using Laravel Eloquent

Viewed 2908

I need help in my project i had a component for cities there is a relation between the cities table and countries table by id how to get the country name for every city in cities component

this is my code in city component

<table id="example" class="display" style="width:100%">
            <thead>
            <tr>
                <th>
                    <label class="form-checkbox">
                        <input type="checkbox" v-model="selectAll" @click="select">
                        <i class="form-icon"></i>
                    </label>
                </th>
                <th>#</th>
                <th>City Name</th>
                <th>Country Name</th>
                <th>Created At</th>
                <th>Updated At</th>
                <th>Edit</th>
                <th>Delete</th>

            </tr>
            </thead>
            <tbody>
            <tr v-if="cities.length > 0" v-for="(city,index) in cities" :id="city.id">
                <td>
                    <label class="form-checkbox">
                        <input type="checkbox" :value="city.id" v-model="selected">
                        <i class="form-icon"></i>
                    </label>
                </td>
                <td>{{index+1 }}</td>
                <td>{{city.name}}</td>
                <td></td>
                <td>{{city.created_at}}</td>
                <td>{{city.updated_at}}</td>
                <td><button class="btn btn-warning" @click="editModal=true;setVal(city.id,city.name,city.country)" data-toggle="modal" data-target="#editcity"><i class="fa fa-pen"></i></button></td>
                <td><button class="btn btn-danger" @click="delcity(city.id)"><i class="fa fa-trash"></i></button></td>


            </tr>
            </tbody>
            <tfoot>
            <tr>
                <th><label class="form-checkbox">
                    <input type="checkbox" v-model="selectAll" @click="select">
                    <i class="form-icon"></i>
                </label></th>
                <th>#</th>
                <th>City Name</th>
                <th>Country Name</th>
                <th>Created At</th>
                <th>Updated At</th>
                <th>Edit</th>
                <th>Delete</th>

            </tr>
            </tfoot>
        </table>

the second part of code in the city component

<script>
export default {
    data(){
        return {
            cities:         [],
            countries:      [],
            id:             '',
            name:           '',
            country_id:     '',
            country_name:   '',
            loading:        false,
            showModal:      false,
            editModal:      false,
            selected:       [],
            selectAll:      false,
            csrf:           document.querySelector('meta[name="csrf-token"]').getAttribute('content')
        }
    },
    methods:{
        getCities(){
            let url = '/dashboard/getCities';
            axios.get(url).then(res=>{
                let link = this;
                this.cities = res.data;
                /*this.cities.forEach(function(item) {
                    link.getCountryName(item.country_id);
                });*/
            })
        },
        getCountryName(id){
            axios.get('/dashboard/getCountryName/'+id).then(res=>{
                console.log(res.data.success);
                this.country_name = res.data.success;
            });
        },
        getCountries(){
            axios.get('/dashboard/getCountries').then(res=>{
                this.countries = res.data;
            })
        },

     },

    mounted() {
        this.getCities();
        this.getCountries();
    }
}

the two functions getcities and get country name in the citiescontroller

public function getCities(){
    $cities = City::orderBy('id','desc')->get();
    return response()->json($cities);
}
public function getCountryName($country_id){
    $country = DB::table('countries')->where('id','=',$country_id)->first();
    return response()->json(['success'=> $country->name],200);
}

Relationship code in Country Model

public function cities(){
    return $this->hasMany('App\Models\City');
}

Relationship code in City Model

public function countries(){
        return $this->hasMany('App\Models\City');
    }
2 Answers

I think you are overcomplicating what should be pretty simple. If your Eloquent relationships are setup correctly, it is relatively trivial to include fields from the Country model in the serialization of the related City model.

Your relationships should look something like this:

City.php

<?php

...

class City extends Model
{
  ...

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

Country.php

<?php

...

class Country extends Model
{
  ...

  public function Cities
  {
    return $this->hasMany('App\Models\City');
  }
}

NOTE: This setup requires a country_id column on the cities table

You currently have defined this relationship as a many-to-many, which doesn't make much sense, considering the context. A City does not have many Countries. It belongsTo exactly one Country. The other side is fine, since a Country does have many Cities. Therefore, what you want here is a one-to-many relationship.

Once your model relationships are setup correctly, you can easily get the Country name for any City. I would do it like this:

City.php

<?php

...

class City extends Model
{
  ...

  protected $with = ['country'];
}

This means that any time a City is loaded from the database, its related Country is eager loaded.

Alternatively, you can eager load the related Country when you load all of the Cities:

citiescontroller

public function getCities(){
    $cities = City::with('country')
                  ->orderBy('id','desc')
                  ->get();

    return response()->json($cities);
}

Regardless of which implementation you choose, your City component can access the Country's fields through the City model:

<tr v-if="cities.length > 0" v-for="(city,index) in cities" :id="city.id">

  ...

  <td>{{ city.country.name }}</td>

  ...

</tr>

Relationship code in City Model

update this

public function countries()
{
  return $this->hasMany('App\Models\City');
}

to

public function country()
{
  // return $this->belongsTo('App\Models\Country');
  return $this->belongsTo(Country::class);
}

by the way you should rename countries to country

Related