Laravel API APP多对多关系,如何以JSON返回特定信息? [英] Laravel API APP Many-Many Relationship, how to return specific information in JSON?
问题描述
一段时间以来,我一直在试图解决这个问题.基本上我有2个模型"Recipe",成分"和一个控制器"RecipeController". 我正在使用Postman来测试我的API.当我转到使用RecipeController @ getRecipe的获取路线时,返回值如下图所示:
I been trying to figure this out for some time now. Basically i got 2 models ' Recipe ', ' Ingredient ' and one Controller ' RecipeController ' . I'm using Postman to test my API. When i go to my get route which uses RecipeController@getRecipe, the return value is as per the pic below:
如果我希望获取路线的返回值在下图的格式中,我该如何实现?通过这种方式,我的意思是我不想看到配方:created_at列,updated_at列以及配料:枢轴信息列,只想要名称和金额列信息.
If i want the return value of the get route to be in the FORMAT of the below pic, how do i achieve this? By this i mean i don't want to see for the recipes: the created_at column, updated_at column and for ingredients: the pivot information column, only want name and amount column information.
食谱模型:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Recipe extends Model
{
protected $fillable = ['name', 'description'];
public function ingredients()
{
return $this->belongsToMany(Ingredient::class,
'ingredient_recipes')->select(array('name', 'amount'));
}
}
成分模型:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ingredient extends Model
{
protected $fillable = ['name', 'amount'];
}
RecipeController
RecipeController
<?php
namespace App\Http\Controllers;
use App\Ingredient;
use App\Recipe;
use Illuminate\Http\Request;
class RecipeController extends Controller {
public function postRecipe(Request $request)
{
$recipe = new Recipe();
$recipe->name = $request->input('name');
$recipe->description = $request->input('description');
$recipe->save();
$array_ingredients = $request->input('ingredients');
foreach ($array_ingredients as $array_ingredient) {
$ingredient = new Ingredient();
$ingredient->name = $array_ingredient['ingredient_name'];
$ingredient->amount = $array_ingredient['ingredient_amount'];
$ingredient->save();
$recipe->ingredients()->attach($ingredient->id);
}
return response()->json(['recipe' => $recipe . $ingredient], 201);
}
public function getRecipe()
{
$recipes = Recipe::all();
foreach ($recipes as $recipe) {
$recipe = $recipe->ingredients;
}
$response = [
'recipes' => $recipes
];
return response()->json($response, 200);
}
API路由:
Route::post('/recipe', 'RecipeController@postRecipe')->name('get_recipe');
Route::get('/recipe', 'RecipeController@getRecipe')->name('post_recipe');
谢谢你们!
推荐答案
我认为您最好的解决方案是使用Transformer.使用当前的实现,我建议您仅提取循环中所需的字段,即:
I think your best solution is using Transformer. Using your current implementation what I would recommend is fetching only the needed field in your loop, i.e:
foreach ($recipes as $recipe) {
$recipe = $recipe->ingredients->only(['ingredient_name', 'ingredient_amount']);
}
尽管上述方法可能有效,但是由于将要进行大量的迭代/循环轮询数据库,因此当前的实现存在问题,我建议您急于加载该关系. 但是出于这个问题,您只需要 Transformer .
While the above might work, yet there is an issue with your current implementation because there will be tons of iteration/loop polling the database, I would recommend eager loading the relation instead. But for the sake of this question, you only need Transformer.
使用作曲器composer require league/fractal
安装转换器,然后可以在app
目录下创建一个名为Transformers
的目录.
Install transformer using composer composer require league/fractal
Then you can create a directory called Transformers
under the app
directory.
然后创建一个名为RecipesTransformer的类,并使用以下代码进行初始化:
Then create a class called RecipesTransformer, and initialize with:
namespace App\Transformers;
use App\Recipe;
use League\Fractal\TransformerAbstract;
class RecipesTransformer extends TransformerAbstract
{
public function transform(Recipe $recipe)
{
return [
'name' => $recipe->name,
'description' => $recipe->description,
'ingredients' =>
$recipe->ingredients->get(['ingredient_name', 'ingredient_amount'])->toArray()
];
}
}
然后,您可以像下面这样在控制器方法中使用此转换器:
Then you can use this transformer in your controller method like this:
use App\Transformers\RecipesTransformer;
......
public function getRecipe()
{
return $this->collection(Recipe::all(), new RecipesTransformer);
//or if you need to get one
return $this->item(Recipe::first(), new RecipesTransformer);
}
您可以参考一个很好的教程喜欢以获取更多灵感,或直接访问分形"页面以获取详细信息.
You can refer to a good tutorial like this for more inspiration, or simply go to Fractal's page for details.
更新
为了使Fractal集合正常工作,因为如果您的项目中包含Dingo API,那么我给出的示例将可以正常工作,您可以通过以下方式手动创建它:
In order to get Fractal collection working since the example I gave would work if you have Dingo API in your project, you can manually create it this way:
public function getRecipe()
{
$fractal = app()->make('League\Fractal\Manager');
$resource = new \League\Fractal\Resource\Collection(Recipe::all(), new RecipesTransformer);
return response()->json(
$fractal->createData($resource)->toArray());
}
如果您要制作一个Item而不是Collection,则可以使用new \League\Fractal\Resource\Item
.我建议您安装Dingo API或遵循此简单的教程,以便在没有不必要的重复的情况下进行更整洁的处理
In case you want to make an Item instead of collection, then you can have new \League\Fractal\Resource\Item
instead. I would recommend you either have Dingo API installed or you can follow this simple tutorial in order to have in more handled neatly without unnecessary repeatition
这篇关于Laravel API APP多对多关系,如何以JSON返回特定信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!