When returning a model using resource created_at and updated_at casting is working fine,
but when i modify the toArray() function the casting is not working !
in my model :
protected $casts = [
'created_at' => 'datetime:Y-m-d:h',
'updated_at' => 'datetime:Y-m-d:h',
];
in resource :
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'value' => $this->value,
'box' => new BoxResource($this->box),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
in controller :
public function index(Request $request)
{
return CurrencyResource::collection(
Currency::where("user_id", "=", $request->user()->id)
->paginate($per_page)
);
}
How to make the casting work ?
By it not working, you mean the timestamps revert to carbon instances? You could just use the format method then.
'created_at' => $this->created_at->format('Y-m-d:h'),
'updated_at' => $this->updated_at->format('Y-m-d:h'),
Related
i have an array with values that i am trying to insert it in the database, but when i use create() the values are inserted as null in database while if i use insert() the values insert correct.
This is the code from the controller
public function store(Request $request)
{
$request->validate([
'order_number' => 'required',
'client' => 'required',
'products' => 'required',
'amount' => 'required',
'description' => 'required',
]);
for($i = 0; $i < count($request->products); $i++)
{
$values[] = [
'order_number' => $request->order_number,
'client' => $request->client,
'products' => $request->products[$i],
'amount' => $request->amount[$i],
'description' => $request->description
];
}
Order::create($values);
return redirect('/')->with('msg', 'Order Saved successfully!');
}
and this is the code from the model
public $timestamps = true;
protected $fillable = [
'order_number',
'client',
'products',
'amount',
'description',
];
The names are the same and in the database, any reason why the values come null when i use create() method?
insert() method accepts multiple objects in form of arrays to be created, for example :
DB::table('users')->insert([
['email' => 'picard#example.com', 'votes' => 0],
['email' => 'janeway#example.com', 'votes' => 0],
]);
But create() method does not accept such structure. You cannot create multiple entries using this method. So in this case you either keep using insert(), either move your create() inside for loop.
Edit : createMany() works only on relationships, and apparently DB manipulation in loops is antipattern. In that case you can do something like this :
$created_at = now();
for($i = 0; $i < count($request->products); $i++)
{
$values[] = [
'order_number' => $request->order_number,
'client' => $request->client,
'products' => $request->products[$i],
'amount' => $request->amount[$i],
'description' => $request->description,
'created_at' => $created_at,
'updated_at' => $created_at,
];
}
Order::insert($values);
I'm just learning laravel. I want update key / value in database with laravel api but not work.
My products model is one to many with ProductMeta and many to many with contents model.
My Models
class Product extends Model
{
use HasFactory;
protected $guarded = [];
public function productMeta()
{
return $this->hasMany(ProductMeta::class);
}
public function content()
{
return $this->belongsToMany(Content::class, 'product_contents')->withTimestamps();
}
}
class ProductMeta extends Model
{
use HasFactory;
protected $guarded = [];
public function products()
{
return $this->belongsTo(Product::class);
}
}
class Content extends Model
{
use HasFactory;
protected $guarded= [];
public function product()
{
return $this->belongsToMany(Product::class, 'product_contents');
}
Controller
public function update(Request $request, $id)
{
$product = Product::findOrFail($id);
DB::table('product_metas')
->upsert(
[
[
'product_id' => $product->id,
'key' => 'name',
'value' => $request->name,
],
[
'product_id' => $product->id,
'key' => 'price',
'value' => $request->name,
],
[
'product_id' => $product->id,
'key' => 'amount',
'value' => $request->name,
],
],
['product_id','key'],
['value']
);
return \response()->json([], 204);
}
Table Structure
API parameter
I tried with update and updateOrcreate and updateOrInsert and upsert methods.
just in upsert method writed database but inserted new data.not updated.
In your case, you should use updateOrCreate() instead of upsert.
Product::updateOrCreate([
'product_id' => $id,
'name' => $request->name,
'price' => $request->price,
'amount' => $request->amount
]);
or
Product::upsert([
[
'product_id' => $id,
'name' => $request->name,
'price' => $request->price,
'amount' => $request->amount
]
], ['product_id'], ['name', 'price', 'amount']);
In addition your problem is your table name is not matching with your structure table name. In your controller DB::table('product_metas') should be DB::table('products_meta').
my problem solved this way:
ProductMeta::query()->where('product_id', $id)->upsert([
['product_id' => $id, 'key' => 'name', 'value' => $request->name],
['product_id' => $id, 'key' => 'price', 'value' => $request->price],
['product_id' => $id, 'key' => 'amount', 'value' => $request->amount]],
['product_id'], ['value']);
$contentRecord = Product::find($id);
$contentRecord->content()->update(['path'=>$request->path]);
return response()->json([], 204);
I forget use query() method for ProductMeta and added $table->unique(['product_id', 'key']); to product meta migration.
**products relation one to many with product Meta
And Many to many with content.
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);
}),
];
}
The resource collection:
public function toArray($request)
{
return [
'test' => 55,
'id' => $this->id,
'name_en' => $this->name_en,
'name_ar' => $this->name_ar,
'slug' => $this->slug,
'details' => $this->details,
'currency' => $this->currency,
'offer' => $this->offer->first(),
'brand' => $this->brand,
'category' => $this->category,
'specifications' => SpesificationResource::collection($this->specifications),
'merchant' => $this->merchant,
'images' => count($this->images) > 0 ? ImageResource::collection($this->images) : asset("/images/default.png"),
"price" => $this->price,
"finalPrice" => $this->offer->first() ? $this->price - ($this->price * $this->offer->first()->discount / 100) : $this->price,
'quantity' => $this->quantity,
'inStock' => $this->inStock(),
'status' => $this->status,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
The controller:
public function show($id)
{
try {
$product = new ProductResource(Product::findOrFail($id));
return $product->test;
// return JsonResponse::respondSuccess(trans(JsonResponse::MSG_SUCCESS), $product);
} catch (\Exception $e) {
return JsonResponse::respondError($e->getMessage());
}
}
when I use the test value inside the controller it's not returned, although it returned when I call it from Postman.
What the problem here?
$product is an instance of ProductResource And of course there is no test property on that class. And it does not implement the magic __get method.
So what you can do is either use $product['test'] cause it implements ArrayAccess or first you can do $product = (new ProductResource(Product::findOrFail($id)))->toArray($request); Then again you can use $product['test'] to get the test value.
i am new to Laravel i need some help in validation. i have two fields one is for country code and other is for phone number and they are being stored separately in respective column in database. i want to validate phone number as unique what i want is get phone number (1234567) country_Code(+12) join them as one like (+121234567) and then validate(unique) against db columns country_Code(+12) + phone(1234567). how can i achieve this?
here is my validation rules method for custom form request
public function rules()
{
return [
'first_name' => 'required|string',
'last_name' => 'required|string',
'email' => ['required', Rule::unique('clients')->ignore($this->client)],
'country_code' => 'required',
'phone' => ['required',Rule::unique('clients')->ignore($this->client)],
'receive_video_lessons' => 'required|boolean'
];
}
You could use a custom rule. Try something like this:
public function rules()
{
return [
'first_name' => ['required', 'string'],
'last_name' => ['required', 'string'],
'email' => ['required', Rule::unique('clients')->ignore($this->client)],
'country_code' => ['required'],
'phone' => ['required', new IsValidPhoneNumber($this->country_code, $this->client)],
'receive_video_lessons' => 'required|boolean'
];
}
Then in your custom validation rule:
class IsValidPhoneNumber implements Rule
{
protected $countryCode;
protected $clientId;
public function __construct($countryCode, $clientId)
{
$this->countryCode = $countryCode;
$this->clientId = $clientId;
}
public function passes($attribute, $value)
{
return ! Client::where('country_code', $this->countryCode)
->where('phone', $value)
->where('client_id', '!=', $this->clientId)
->exists();
}
public function message()
{
return 'This :attribute is not valid.';
}
}
You might have to massage it to work but you get the idea.