i want to make two different functions on resource so that i can get a two different response .i.e i want the resource to return data without image and with image.
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'area_code' => $this->area_code
];
}
public function toArrayWithImages($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'area_code' => $this->area_code,
'image' => $this->image
];
}
this is what i tried but dont know how to point to the second function 'toArrayWithImages' . can someone explain me this ?
This is my controller ..
public function getAllBusinessAreas()
{
try {
$areas = Area::orderBy('id', 'desc')->get();
return BusinessAreaResource::collection($areas);
} catch (Exception $e) {
return sendErrorResponse('Error fetching Business Areas', true, 500);
}
}
what it does is by default it hits the toArray function i want to be specific which function to hit from controller. is it possible to do it ?
So basically what i am doing is adding an additional parameter to your request, you can use a flash session variable as well if it is not possible to attach extra params to your request, to filter weather it goes to the function which returns image or data without image.
public function toArray($request)
{
if($request->with_image)
{
this::toArrayWithImages($request->except('with_image'));
}
else
{
this::toArrayWithoutImages($request->except('with_image'));
}
}
public function toArrayWithoutImages($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'area_code' => $this->area_code
];
}
public function toArrayWithImages($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'area_code' => $this->area_code,
'image' => $this->image
];
}
Related
I use laravel 8 & have 3 table:
Products, ProductPrice & ProductsPublisher:
this is my Products model for this relationship:
public function lastPrice(){
return $this->hasMany(ProductPrice::class)->where('status','active')->orderBy('created_at','DESC')->distinct('publisher_id');
}
and this is my productsPrice model for publisher relationship:
public function getPublisher(){
return $this->belongsTo(ProductsPublisher::class,'publisher_id');
}
now, i want to use laravel resource for my api, i wrote products resource:
public function toArray($request)
{
return [
'id' => $this->id,
'price' => lastPrice::make($this->lastPrice),
'status' => $this->status,
'slug' => $this->slug,
'title' => $this->title,
'description' => $this->description,
'txt' => $this->txt,
'lang' => $this->lang,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
but in lastPrice resource, when i wrote like this:
return [
'id' => $this->id,
'main_price' => $this->main_price
];
it give me this error:
Property [id] does not exist on this collection instance.
when i use this code:
return parent::toArray($request);
get response but because i need to use another relationship in my lastPirce for publishers, i cant use that code and should return separately my data.
What i should to do?
thanks
Edit 1:
this is my Controller Code:
$products = Product::where('id',$id)->where('slug',$slug)->where('status','confirm')->first();
if(!$products){
return $this->sendError('Post does not exist.');
}else{
return $this->sendResponse(new \App\Http\Resources\Products\Products($products), 'Posts fetched.');
}
and this is sendResponse & sendError:
public function sendResponse($result, $message)
{
$response = [
'success' => true,
'data' => $result,
'message' => $message,
];
return response()->json($response, 200);
}
public function sendError($error, $errorMessages = [], $code = 404)
{
$response = [
'success' => false,
'message' => $error,
];
if(!empty($errorMessages)){
$response['data'] = $errorMessages;
}
return response()->json($response, $code);
}
thanks.
Edit 2:
i change my lastPrice Resource toArray function to this and my problem solved, but i think this isn't a clean way, any better idea?
$old_data = parent::toArray($request);
$co = 0;
$new_data = [];
foreach ($old_data as $index){
$publisher_data = Cache::remember('publisher'.$index['publisher_id'], env('CACHE_TIME_LONG') , function () use ($index) {
return ProductsPublisher::where('id' , $index['publisher_id'])->first();
});
$new_data[$co]['main_prices'] = $index['main_price'];
$new_data[$co]['off_prices'] = $index['off_price'];
$new_data[$co]['publisher'] = SinglePublisher::make($publisher_data);
$new_data[$co]['created_at'] = $index['created_at'];
$co++;
}
return $new_data;
I'm developing an API with Laravel. In one of the endpoint I'm accessing, some fields are showing a null value, but it should have some information.
Note the "addicionais_descricao" and "valor" fields, both always come with null values when I include them in the attributeitems array, but if I leave it at the initial level, the data is presented, but it doesn't solve my case, because I need this information with the attribute items:
enter image description here
This is where the endpoint calls, I make the query in the "Attribute" table, which has a relationship with the "Attributeitems" table, while the "attributeitems" table is linked to "Attribute" and "product".
public function show($id)
{
$atributos = Atributo::query('atributo')
->select(
'atributo.id',
'atributo.atrdescricao',
'atributoitens.atributo_id',
'atributoitens.produto_id',
'produto.prodescricao',
'produto.provalor'
)
->leftJoin('atributoitens', 'atributo.id', '=', 'atributoitens.atributo_id')
->leftJoin('produto', 'produto.id', '=', 'atributoitens.produto_id')
->where('atributo.id', '=', $id)
->get()->unique('id');
return AtributoResource::collection($atributos);
}
Resource Atributo:
public function toArray($request)
{
return [
'id' => $this->id,
'descricao' => $this->atrdescricao,
'atributoitens' => AtributoitensResource::collection($this->atributoitens),
];
}
Resource Atributo Itens:
public function toArray($request)
{
return [
'id' => $this->id,
'atributo' => $this->atributo_id,
'produtos' => $this->produto_id,
'adicionais_descricao' => $this->prodescricao,
'valor' => $this->provalor
];
}
What is the correct procedure for this situation?
Take this example as a reference :
Controller
$data = $shop->products()
->whereStatus(true)
->where('product_shop.active', true)
->where('product_shop.quantity', '>=', $this->min_product_qty)
->paginate(50);
return (new ProductCollection($data))
->response()
->setStatusCode(200);
ProductCollection
public function toArray($request)
{
return [
'data' => $this->collection
->map(function($product) use ($request) {
return (new ProductResource($product))->toArray($request);
}),
'brand' => $this->when($request->brand, $request->brand)
];
}
ProductResource
public function toArray($request)
{
return [
'type' => 'product',
'id' => (string) $this->id,
'attributes' => [
'uuid' => $this->uuid,
'name' => $this->name,
'slug' => $this->slug,
'description' => $this->description,
'thumb_path' => $this->thumb_path,
'cover_path' => $this->cover_path,
],
'relationships' => [
'brand' => $this->brand
]
];
}
Something like this should help you do what you want. I cant exactly do it for you. by the way why you are not using Eloquent, something like
Attribute::where(...)->with(['relation_1', 'products'])->get();
public function toArray($request)
{
return [
'id' => $this->id,
'attributes' => [...],
'products' => $this->collection
->map(function($this->product) use ($request) {
return (new ProductResource($product))->toArray($request);
}),
];
}
Hi I'm trying to get data and mapping it in resources, but somehow I'm getting error ErrorException: Trying to get property name of non-object. I'm already define the relationship in models, but somehow I'm still getting the error.
User Models
public function shop()
{
return $this->hasOne(Shop::class);
}
Shop Models
public function user()
{
return $this->belongsTo(User::class);
}
And I'm using the resources (ShopCollection) in controller when getting data like this
public function index()
{
return new ShopCollection(Shop::all());
}
This is how I mapping the data in ShopCollection
public function toArray($request)
{
return [
'data' => $this->collection->map(function($data) {
return [
'id_toko' => $data->id,
'name' => $data->name,
'user' => [
'name' => $data->user->name,
'email' => $data->user->email,
'avatar' => $data->user->avatar,
'avatar_original' => $data->user->avatar_original
],
'logo' => api_asset($data->logo),
...
];
})
];
}
Sorry about my english and thank you for your kind help
ErrorException: Trying to get property name of non-object
This very common error is also pretty simple to debug: somewhere, one of your variables is null but you are still trying to use one of it's property.
It is very likely, from what we can see in your code, that $data->user returns null at some point.
It's hard to tell when and where since you didn't provided the line, but I'm confident that's the case.
Since your resource is a Collection, Laravel iterates through it.
You can catch the problematic entry by adding:
public function toArray($request)
{
return [
'data' => $this->collection->map(function($data) {
if($data->user == null){
dd($data);
};
return [
'id_toko' => $data->id,
'name' => $data->name,
'user' => [
'name' => $data->user->name,
'email' => $data->user->email,
'avatar' => $data->user->avatar,
'avatar_original' => $data->user->avatar_original
],
'logo' => api_asset($data->logo),
...
];
})
];
}
This is answer assumes the problem is from $data->user. If that's not the case, edit your question with the full error stack trace.
Thanks to #toyi answer I can found out what is the problem.
The reason why I got the error is because some of shops have null user_id. So to handle it I check it first before using it.
This is the code:
public function toArray($request)
{
return [
'data' => $this->collection->map(function($data) {
$user = $data->user ? [
'name' => $data->user->name,
'email' => $data->user->email,
'avatar' => $data->user->avatar,
'avatar_original' => $data->user->avatar_original
] : [];
return [
'id_toko' => $data->id,
'name' => $data->name,
'user' => $user,
'logo' => api_asset($data->logo),
...
I am sending some data with formData, and for one fields (object) I use: JSON.stringify(this.allValues).
and I try to validate all values from this.allValues .
Till now I tried 2 methods from here , now I try with the second one with "JsonApiMiddleware" .
But with this I validation(required) errors, even if the fields are not null.
public function rules()
{
$newValues = json_decode(request()->get('all_values')); // Here I have all values that needs to be validated
dd($newValues); // I post the respons for this below
$newValues = [
'saleforce_id' => 'required',
'customer_id' => 'required',
]
return $newValues;
}
""customer_id":49,"saleforce_id":"","lkp_invoicing_method_id":3,"lkp_product_category_id":10,"lkp_notice_period_id":5,"lkp_licence_term_id":9,"is_attrition_risk":false,"is_additional_users":false,"contract_value_exc_vat_annual":"257590...and many more
Treat the JSON object you send as a php associative array. For example let's say your sent data looks like this.
/* var allValues = */
{
data: {
requiredField1: value,
requiredField2: value,
requiredArrayField1: [
1,
2,
3,
],
optionalField1: value
}
}
Then, you can validate the data like this:
public function rules()
{
return: [
'data' => 'required|array',
'data.requiredField1' => 'required',
'data.requiredField2' => 'required',
'data.requiredArrayField1' => 'required|array',
'data.requiredArrayField1.*' => 'required|numeric',
'data.optionalField1' => 'nullable',
];
}
I found a solution.
I use the method from laracast, fureszpeter, method with middleware, and I edit it.
public function handle($request, Closure $next)
{
if ($request->has('all_values')) {
$request->merge([
'all_values' => json_decode($request->get('all_values'), true)
]);
} // only when I have all_values in my request
return $next($request);
}
}
In my existing Request:
public function rules()
{
$newValues = [
'all_values.saleforce_id' => 'required'
'all_values.customer_id' => 'required',
// and the rest of the files
]
return $newValues
}
I have this Model UserSetting.php:
class UserSetting extends Model
{
protected $fillable = ['user_id', 'name', 'setting_value'];
public static function set($user_id, $name, $value)
{
if (!User::find($user_id)) {
return error('NoForeign_User');
}
self::updateOrCreate(
['user_id' => $user_id, 'name' => $name],
['setting_value' => $value]
);
}
}
And I want to use it this way inside UserSettingController.php:
public function user(Request $request)
{
Validator::make($request->all(), [
'user_id' => 'required|int',
'name' => 'required|string',
'setting_value' => 'required|string',
], $this->messages)->validate();
// HERE IS THE CALL
UserSetting::set($request->user_id, $request->name, $request->setting_value);
return saved();
}
I need to call UserSetting statically but NOT with a return:
return UserSetting::set(...)
But when the static function gets to the if(!User::find($user_id)) it carries on and shows the saved() helper instead of the return error('NoForeign_User')
While if I do it with a return return UserSetting::set(...) it correctly shows the error.
Is this correct? Do I have any other option other then returning the static class?
EDIT:
My error() function is this:
function error($message, $code = 422)
{
$response = ['message' => $message];
if ($errors) {
$response += [
'errors' => $errors,
];
}
return response()->json([
'message' => $message,
], $code);
}
If you don't check the result that is being returned when calling the static method, then for sure the program will continue to execute the next line which is the saved() method in your case.
In order to stop execution a better approach is to throw an exception which will propagate to the Exception handler and stop the function execution.
So instead of this:
if (!User::find($user_id)) {
return error('NoForeign_User');
}
try this:
if (!User::find($user_id)) {
throw new \Exception('NoForeign_User');
}
or yet another and the best approach in my opinion that I just remembered is to simply use the findOrFail function:
User::findOrFail($user_id);
This will also throw an exception if the user has not been found.