laravel中的嵌套资源

时间:2016-10-31 00:15:42

标签: php laravel eloquent

我正在构建我的API(品牌和型号),我希望拥有嵌套资源(不确定这是否正确)。

/使/法拉利/模型 /使/法拉利/模型/ F40

我定义了以下路线

Route::resource('makes.models', 'ModelsController');

和ModelsController.php

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $data = Models::all();
    return response()->json($data);
}

/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function show($id)
{
    $data = Models::find($id);
    return response()->json($data);
}

和模型模型(是的,我需要更改名称)

class Models extends Model
{

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

我的问题是,即使路线有效,它也会返回数据库中的所有模型(不仅仅是法拉利),我应该在哪里定义这种关系?不是自动的吗? 我有2个表make(id,name),models(id,name,make_id)

谢谢你!

2 个答案:

答案 0 :(得分:1)

资源路由将定义以下路由:

Method  Path                               Action 
GET     /makes/{make}/models               index   
GET     /makes/{make}/models/create        create  
POST    /makes/{make}/models               store 
GET     /makes/{make}/models/{id}          show   
GET     /makes/{make}/models/{id}/edit     edit    
PUT     /makes/{make}/models/{id}          update  
DELETE  /makes/{make}/models/{id}          destroy 

您的请求/品牌/法拉利/型号与这些路线中的任何一条都不匹配(因为您的show参数只接受一个参数)。您可以请求/ makes / models / 1来调用show,但实际上您缺少此路由,因为嵌套路由不提供它。

如果你说你总是得到所有项目,你很可能会点击索引动作而不是显示。

如果您想使用/ makes / ferrari / models / f40查询模型,您需要这样的路线:

Route::get('/makes/{make}/model/{model}', 'ModelsController@show');

这已经是为您创建的资源路径的一部分。 现在,在show controller中,使用make和model参数来查找正确的数据集:

public function show($make, $model)
{
    $data = Model::with('makes')
               ->whereName($model)
               ->whereHas('makes', function ($query) use ($make) {
                                      $query->where('name', '=', $make); 
                                   })->get();

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

Laravel不会自动为你做这件事。

更新:路线模型绑定

您可能需要查看https://laravel.com/docs/5.3/routing#route-model-binding以了解更为复杂的方法。您可以在两个模型中设置路线密钥名称,覆盖getRouteKeyName()方法并返回' name'在这种情况下,告诉Laravel使用name列而不是id。

您还可以通过执行类似

的操作将路径中的参数专门绑定到自定义分辨率逻辑
$router->bind('model', function ($value) {
    return Model::where('name', $value)->first();
});

然后每次在路线中使用{model}时,都会使用名称而不是ID。

使用slugs

但是,请注意,您必须确保存储在数据库中的model和make的名称已经过时,以便它们适合在URL中使用。如有必要,您可以在绑定中执行此操作,如上所示,返回

return str_slug(Model::where('name', $value)->first());

然而,这是未经测试的,因此可能会或可能不会。

希望有所帮助: - )

答案 1 :(得分:0)

使用嵌套资源时,所有控制器操作都将收到额外的第一个参数(父资源标识符)。因此,您需要相应地更新控制器操作:

public index($make) {
    $make = Make::with('models')->where('name', $make)->firstOrFail();

    return view('models.index', compact('make'));
}

public show($make, $model) {
    $make = Make::with('models')
        ->where('name', $make)
        ->firstOrFail();
    $model = $make->models()
        ->where('name', $make)
        ->firstOrFail();

    return view('models.show', compact('make', 'model'));
}

它应与您的其他控制器操作相同。

请注意,我对数据库的结构做了假设。