我正在使用Laravel 5.7和mysql。我有一个services
表和一个allowed_locations
表,其中包含每个城市提供的服务。 1个或多个城市可以使用1种服务。每个城市属于一个州,每个州属于一个国家。我想返回服务,城市,州和国家/地区,但是我不确定如何在每个模型中建立关系。我可以检索城市,州和国家/地区吗?
城市
id
state_id
状态
id
country_id
name
国家/地区
id
name
服务
id
name
允许的位置
city_id (id from cities table)
service_id (id from Services table)
国家 身份证,姓名 1,美国
状态
id, country_id, name
3, 1, California
4, 1, Washington
5, 1, Oregon
城市
id, state_id, name
1, 3, San Diego
2, 4, Seattle
3, 5, Portland
服务
id, name
1, Tax Services
2, Legal Services
允许的位置
city_id, service_id
1, 1
2, 1
3, 2
Services.php模型
public function locations () {
return $this->belongsToMany('App\cities', 'services_by_location', 'service_id','city_id');
}
cities.php模型
public $with = ['state'];
public function state() {
return $this->hasOne(states::class, 'id', 'state_id');
}
states.php模型
public $with = ['country'];
public function country() {
return $this->hasOne(Countries::class, 'id', 'country_id');
}
Countries.php模型
//
AllowedLocations.php模型
//
控制器
$data = Services::with(['locations'])->get();
return response()->json($data, 200);
目前我正在返回这样的回复
{
{
id: 1,
name: Tax Services
locations:
{
{
city_id: 1,
city: San Diego,
state: {
name: California
}
country: {
name: USA,
}
},
{
city_id: 2,
city: Seattle,
state: {
name: Washington
}
country: {
name: USA,
}
},
}
},
{
id: 2,
name: Legal Services
locations:
{
{
city_id: 3,
city: Portland,
state: {
name: Oregon
}
country: {
name: USA,
}
},
}
}
}
我想返回嵌套嵌套数组中的城市,州和国家/地区名称,而不是嵌套的state
和country
。这可能吗?
{
{
id: 1,
name: Tax Services
locations:
{
{
city_id: 1,
city: San Diego,
state: California,
country: USA
},
{
city_id: 2,
city: Seattle,
state: Washington,
country: USA
},
}
},
{
id: 2,
name: Legal Services
locations:
{
{
city_id: 3,
city: Portland,
state: Oregon,
country: USA
},
}
}
}
答案 0 :(得分:1)
这是一个有趣的挑战,因此我在测试机上进行了设置并将其解决。毫无疑问,还有其他方法可以执行此操作,但这可以起作用,并且可以根据需要在最高级别使用州和国家/地区。
这些参数不会显示在dd()
转储中,尽管它们可以在顶层直接访问,而 会在您通过JSON转储时显示。 / p>
我认为最简单的帮助方法是在City模型上设置访问器。然后,从“服务”模型调用locations()
方法时,所有城市都会获得您所需的信息。
城市模型:
protected $fillable=[
'name',
'state_id',
];
protected $appends = ['state_name', 'country_name'];
public function state() {
return $this->hasOne(State::class, 'id', 'state_id');
}
public function getStateNameAttribute ()
{
return $this->state->name;
}
public function getCountryNameAttribute ()
{
return $this->state->country->name;
}
请注意protected $appends = ['state_name', 'country_name'];
。当您转储到JSON时,这将显示那些额外的字段。如果您只需要访问其他字段(state_name
和country_name
),则不需要此行-您现在可以从数组的“城市”级别部分中提取字段,因为城市模型中的访问器。
查询现在需要包含一些更急切的加载,以便那些访问器不会尝试从空值获取名称。 (您应该在访问器中添加一个空检查)我建议一次将其全部拉入:
$data = \App\Service::with(['locations' => function($query){
$query->with(['state' => function($query){
$query->with('country');
}]);
}])->get();
在$data
上进行for循环将为您提供城市一级所需的一切。例如:
foreach($data as $service){
echo "Service id: ".$service->id.": ";
echo $service->name."<br/>";
echo $service->locations->first()->name.", ";
echo $service->locations->first()->state_name." -- in the country: ";
echo $service->locations->first()->country_name;
echo "<br/><br/><br/>";
}
这成功产生了:
Service id: 1: Tax Services
Annapolis, Maryland -- in the country: USA
Service id: 2: Legal Services
Potomac, Maryland -- in the country: USA
答案 1 :(得分:0)
如果我对您的理解正确,那么您的关系应该像这样:
Service.php
public function cities()
{
return $this->belongsToMany(City::class);
}
City.php
public function services()
{
return $this->belongsToMany(Service::class);
}
public function state()
{
return $this->belongsTo(State::class);
}
如果可能的话,我会坚持使用default并将数据透视表重命名为city_service
State.php
public function cities()
{
return $this->hasMany('App\City');
}
public function country()
{
return $this->belongsTo('App\Country');
}
Country.php
public function states()
{
return $this->hasMany('App\State');
}
为了获得理想的结果,您必须使用accessors
City.php
public function getState ()
{
return $this->state->name;
}
public function getCountry ()
{
$country = Country::findOrFail($this->state->country_id);
return $country->name;
}
现在这有点昂贵,但是hasManyThrough()在这里不起作用,因为您需要反向关系。 proposed已被接受,但未被接受。有一个package,但不确定是否稳定。似乎被遗弃了。
无论如何,您应该可以通过以下方法查询并获得所需结果:
$services = Service::with('cities')->get();