Laravel - create on hasmany not working - php

The inserted row key,value are empty !!
\App\Product::find(1)->getProductMeta()->create([
'key' => 'a key',
'value' => 'a value'
]);
query SQL :
insert into `product_metas` (`product_id`) values (?)
Product:
function getProductMeta(){
return $this->hasMany('App\ProductMeta');
}
ProductMeta:
protected $fillable = ['key','value'];
Migration:
Schema::create('product_metas', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned()->index();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');;
$table->string('key')->index();
$table->text('value')->nullable();
});

I don't see anything wrong with your code. Just try one of these methods to create the relationship item.
Add this to ProductMeta model
protected $fillable = ['key', 'value', 'product_id'];
In your controller do this so that you can get a valid product.
$product = Product::findOrFail(1);
Then
$product->getProductMeta()->create([
'key' => 'a key',
'value' => 'a value'
]);
Or
\App\ProductMeta::create([
'key' => 'a key',
'value' => 'a value',
'product_id' => $product->id
]);
Or
$productMeta = new \App\ProductMeta;
$productMeta->key = 'a key';
$productMeta->value = 'a value';
$productMeta->product_id = $product->id;
$productMeta->save();

i'v solved my problem with remove function __construct in my Model .
I don't know why i'v made a __construct method !

you have to make relation in both models eg. Product model and admin model
for example you say in your product model
public function admin(){
return $this->belongsTo(Admin::class, 'admin_id');
}
and in your admin model
public function product(){
return $this->hasMany(Product::class);
}
like this both tables and models will be related to each other.
PS: I don't know your exact model and tables so i just assume admins as publishers and products as post you can change it to your table names.

Related

General error: 1364 Field 'title' doesn't have a default value while doing update

Hello I faced the following error:
SQLSTATE[HY000]: General error: 1364 Field 'title' doesn't have a default value.
It happens when I try to update amount of views on specific post.
I've just set default value of points while initializing it specified in the model in $attributes table.
Posts table migration:
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->longText('text');
$table->integer('points');
$table->bigInteger('views');
$table->integer('user_id')->unsigned()->nullable();
$table->integer('is_closed');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
});
}
Post model:
const POINTS = 0;
const VIEWS = 0;
const IS_CLOSED = 0;
protected $attributes = [
'points' => self::POINTS,
'views' => self::VIEWS,
'is_closed' => self::IS_CLOSED,
'title' => null,
'text' => null,
'user_id' => null,
];
protected $fillable = [
'title',
'text',
'user_id',
];
My Service where I try to increment the value of views:
public function incrementPostViews($id)
{
$post = $this->post->findOrFail($id);
$post->views++;
return $post->save();
}
I did use the Request rule but only while creating new post:
public function rules()
{
return [
'title' => ['required', 'max:50'],
'text' => ['required', 'max:1000'],
'user_id' => ['numeric', 'nullable'],
];
}
So by default the points, views and is_closed fields are set to 0 while creating new Post. To be honest I do not have any ideas why it is causing an error.
Update:
In Post model I've changed the $attributes array and added title, text and user_id which default value is set to null. Those three fields stays in $fillable array also. I'm not sure if it's the right way to fix it. If it's not, please correct me.
In the migration there are not changes made.
All changes are visible above.
You declared your title item as required in your table but you didn't declare a default value. And your insert operation doesn't give a value for that column, so it fails.
The easiest way to fix this is probably to declare title as nullable instead.
But if you have a good reason to make it required, you'll have to revisit the way you insert your rows so you can offer a value for that column.
You must create THE post first, once that post has been created you can then update its attributes.
$user = Post::create([
'title' => $request->title,
'text' => $request->text,
'points' => 0,
'views' => 0,
'is_closed' => $request->is_closed,
]);

Laravel inserting data in one to many tables

Good morning developers, iam working on ecommerce project using laravel and angular
in laravel i made two tables ( brands - products ) and i need the brand has many products
so i added this function to the Product model
public function brand()
{
return $this->belongsTo(Brand::class);
}
and i added this function to Brand model
public function products()
{
return $this->hasMany(Product::class);
}
the first question is how i could handle the relation in the products table migration file, is this right or there is better way?
$table->unsignedBigInteger('brand_id');
$table->foreign('brand_id')->references('id')->on('brands')->onDelete('cascade');
the second questions is should i define the brand_id in the $fillable products property or not
protected $fillable = ['name', 'brand_id', 'display', 'ram', 'storage', 'rear_cam', 'front_cam', 'img', 'price'];
the third question is how to handle the store product function and note iam using api calls between angular and laravel
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:100', 'display' => 'required|string|max:100', 'ram' => 'required|string|max:100', 'img' => 'required|image|mimes:jpg,png',
'storage' => 'required|string|max:100', 'rear_cam' => 'required|string|max:200', 'front_cam' => 'required|string|max:200',
'price' => 'required'
]);
if ($validator->fails()) {
$errors = $validator->errors();
return response()->json($errors);
}
$img = $request->file('img');
$ext = $img->getClientOriginalExtension();
$name = 'product-' . uniqid() . ".$ext";
$img->move(public_path('uploads/books/'), $name);
$name = $request->name;
$brand_id = $request->brand_id;
$display = $request->display;
$ram = $request->ram;
$storage = $request->storage;
$rear_cam = $request->rear_cam;
$front_cam = $request->front_cam;
$price = $request->price;
$product = Product::create(['name' => $name, 'brand_id' => $brand_id, 'display' => $display, 'img' => $name, 'ram' => $ram, 'storage' => $storage, 'rear_cam' => $rear_cam, 'front_cam' => $front_cam, 'price' => $price]);
$product->brand()->sync($request->brand_id);
$success = 'Product created successfully';
return response()->json($success);
}
when iam trying to store a product it says there is error with the sync function, what function should i use instead of it
Actually you don't need it to sync, In many-to-many relationships require an additional table called pivot table where you Managing Many-to-Many Relationships using attach-detach-sync method but in case you havnt situation like this.
Undo this Line
$product->brand()->sync($request->brand_id);
After Product created successfully. If you simply called products function to Brand model. You will seeing last created product are there.
Ex:-
Brand::with('products')->find($brand_id)
Thanks
the first question is how i could handle the relation in the products table migration file, is this right or there is better way?
It is indeed the good way to handle this.
the second questions is should i define the brand_id in the $fillable products property or not
It all depends on your use case. Typically you only define the attributes the user can modify at will, like his name. The concept of fillable is here to protect you from mass assignment.
For instance:
if I change the name attribute of a check box from accept_newsletter to is_admin
and if a column named is_admin exists
and if is_admin is in the fillable attributes
and you do something like that: $user->update($request->all());
Then I could potentially become an admin.
However, if is_admin isn't in the fillable attributes, you must explicitly do something like: $user->is_admin = $request->is_admin. Which is much more unlinkely to happen involuntarily.
In your case, the person who will add/edit a product will probably be an admin anyway so you can add brand_id to the fillable attributes.
For your third question, since you are using a hasMany relationship on the Brand model and a belongsTo in the Product model, all you have to do is $product->brand()->associate($request->brand_id);.
But keep in mind that here:
product = Product::create(['name' => $name, 'brand_id' => $brand_id, 'display' => $display, 'img' => $name, 'ram' => $ram, 'storage' => $storage, 'rear_cam' => $rear_cam, 'front_cam' => $front_cam, 'price' => $price]);
You already assign the brand_id to the product you are creating (it'll only work if you added brand_id to the fillable attributes). Think of the fillable attributes as "attributes that can be assigned within an array".

store data into pivot table laravel 8

i have manytomany relation ship between categroy and product
category model
class Attribute extends Model implements Auditable
{
use HasFactory, AuditableTrait;
protected $fillable = ['category','sub_categ'];
public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class);
}
}
product model
class Product extends Model implements Auditable
{
use HasFactory, AuditableTrait;
protected $table = 'products';
protected $fillable = ['name','price','description', 'details'];
public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class);
}
}
the pivot table
Schema::create('attributes_products', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->foreignId('product_id')->constrained('products')->onUpdata('cascade')->onDelete('cascade');
$table->foreignId('attribute_id')->constrained('attributes')->onUpdata('cascade')->onDelete('cascade');
});
what should i do after this i did not undrestant how attach will work in pivot table and return it with the product as json response ?
edit
this is the schema i am working on
i want to give each product it's own category
and this is my product controller store function
public function store(Request $request)
{
$request->validate([
'name' => 'required',
'price' => 'required|numeric',
'description' => 'required',
'details' => 'required',
'stocks' => 'required|numeric',
//'discounts' => 'required|numeric'
]);
$product = Product::create($request->only('name','price','description', 'details'));
$product->stocks()->create([
'quantity' => $request->stocks,
'product_id' => $product->id
]);
$product->discounts()->create([
//'discount' => $request->discounts,
'product_id' => $product->id
]);
if($request->hasFile('images'))
{
foreach( $request->file('images') as $file)
{
$file->store('public/products');
$product->images()->create([
'product_id' => $product->id,
'file_path' => $file->hashName()
]);
}
}
$product->categories()->sync([
'product_id' => $product->id,
'attribute_id'=> 1
]);
}
In your product model check your relation.
public function categories()
{
return $this->belongsToMany(Category::class);
}
Also usually the pivot table needs to have only 2 Ids. So in your case only 2 columns: product_id & category_id.
Your table name by convention should be category_product, otherwise, you should specify it on the second parameter on the relationship.
Fix this too, you got a typo on update:
$table->foreignId('attribute_id')->constrained('attributes')->onUpdate('cascade')->onDelete('cascade');
And finally to attach:
$product = Product::find(1);
$product->categories()->attach($categoryId);
All is explained very well on documentation too: https://laravel.com/docs/8.x/eloquent-relationships

Laravel insert data from one table to another table error

Trying to get the product_id from table one then inserting it to table two, but gives back an error
1048 Column 'product_id' cannot be null (SQL: insert into product_details (product_id, category, brand, provider_id) values (, Peripherals, Riders, 1))
Code:
$product = Product::create([
'product_name' => $request['product_name'],
'quantity' => $request['quantity']
]);
$product->save();
$product_id = $product->id;
$productDetails = ProductDetails::create([
'product_id' => $product_id,
'category' => $request['category'],
'brand' => $request['brand'],
'provider_id' => $request['provider_id']
]);
Fillable for productdetails model
protected $fillable = ['product_id', 'category', 'brand', 'provider_id'];
Database structure: (Just remembered, just a while ago I made some changes on my database that was the time when this error popped out.)
Products:
Schema::create('products', function (Blueprint $table) {
$table->increments('product_id');
$table->string('product_name');
$table->integer('quantity');
Product Details:
Schema::create('product_details', function (Blueprint $table) {
$table->integer('product_id')->unsigned();
$table->string('category',255);
$table->string('brand',255);
$table->integer('provider_id')->unsigned();
$table->foreign('product_id')
->references('product_id')
->on('products')
->onDelete('cascade');
$table->timestamps();
});
This has been solved,
It was just a simple mistake on my part. I should've been using 'product_id' at '$product_id = $product->id' instead of 'id'. Apologies to everyone.
Before inserting into ProductDetails check if Product is saved or not. Also check your fillable field in your ProductDetails model whether you have added product_id or not.
$product = Product::create([
'product_name' => $request['product_name'],
'quantity' => $request['quantity']
]);
if($product) {
$productDetails = ProductDetails::create([
'product_id' => $product->id,
'category' => $request['category'],
'brand' => $request['brand'],
'provider_id' => $request['provider_id']
]);
}
Update your fillable field like below:
protected $fillable = ['product_id', 'category', 'brand', 'provider_id'];
Update
If your primary key is product_id, you should call $product->product_id
Hey you have to change your fillable property like this:
protected $fillable = ['product_id', 'category', 'brand', 'provider_id'];
I don't think you need to use save() method. after create() method you can get model object and get the id from it directly but make sure your id in db is id not product_id.
$product = Product::create([
'product_name' => $request['product_name'],
'quantity' => $request['quantity']
]);
if($product){
$productDetails = ProductDetails::create([
'product_id' => $product->id,
'category' => $request['category'],
'brand' => $request['brand'],
'provider_id' => $request['provider_id']
]);
}else{
echo "Something went wrong";
}
You shouldn't run a save() method after running a create; its redundant.
You can run a db transaction in a try and catch to know what exactly is going wrong.
try {
\DB::transaction(function () use($request) {
$product = Product::create([
'product_name' => $request['product_name'],
'quantity' => $request['quantity']
]);
$productDetails = ProductDetails::create([
'product_id' => $product->id,
'category' => $request['category'],
'brand' => $request['brand'],
'provider_id' => $request['provider_id']
]);
});
dd('successful');
} catch (\Exception $e) {
dd( $e->getMessage() );
}
You will need to specify either a fillable or guarded attribute on the model, as all Eloquent models protect against mass-assignment by default.
Fillable you specify which fields are mass-assignable in your model, So in the model you need to add also product_id:
Model:
protected $fillable = ['product_id', 'category', 'brand', 'provider_id'];
////only the field names inside the array can be mass-assign
Automatically assumes your primary key column is going to be id. In order for this to work correctly, you should set your primary key in your model product.php:
protected $primaryKey = 'product_id';

Polymorphic relationships

I've got a master table called Product with the following columns:
id
product_id
product_type
name
price
in_stock
upc
Where ’id' and 'product_id' are unique (id is the PK)
I'll have other tables for different kinds of products (types).
All these other tables will have Product’s properties plus
Other properties on their own depending on the type of product
(I.e. clothing, records, etc.).
So I created a Product model using Polymorphic relationships
as follows:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = [
'product_id',
'product_type',
'name',
'price',
'in_stock',
'upc'
];
public function categorizable()
{
return $this->morphTo();
}
}
And, for instance, a records model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Record extends Model
{
protected $fillable = [
    'artist_id',
    'title',
    'label',
    'code',
    'format',
    'number_of_discs',
    'image',
    'description'
];
public function products()
{
return $this->morphMany('\App\Product', 'categorizable');
}
public function artist()
{
return $this->belongsTo(Artist::class);
}
public function track()
{
return $this->hasMany(Track::class);
}
public function getItemDetails(int $itemId): array {
}
}
Whereas the columns for record are:
id
artist_id
product_id
title
label
This is the best way I could think of relating these tables.
My questions are:
Is there a better approach to this specific problem?
In this case (using polymorphic relationships), how would I insert a product?
How could I query a product in order to return data from
Both product table and record table? I mean, not a raw query
Since that I can do, but how to perform this query using
Eloquent?
Your code is perfect except product_id column in Record. You don't need that column, just remove it
how would I insert a product?
$product = Product::create([
'name' => $request->name,
'price' => $request->price,
'in_stock' => $request->in_stock
]);
$record->products()->save($product);
OR
$record->products()->create([
'name' => $request->name,
'price' => $request->price,
'in_stock' => $request-> in_stock,
'product_id' => $record->id,
'product_type' => get_class($record)
]);
If you need to create both then do it like this
$record = Record::create([
'artist_id' => $request->artist_id
'title' => $request->title,
'label' => $request->label,
'code' => $request->code,
]);
$product = Product::create([
'name' => $request->name,
'price' => $request->price,
'in_stock' => $request->in_stock
]);
$record->products()->save($product);
Fetch Data
$product = Product::with('categorizable')->find(2);
$product->categorizable; //this will be either Record, Cloth... instance
Similarly for record
$record = Record::with('products')->find(1);
$record->products; //it will give you product collection
For details you can look https://laravel.com/docs/5.1/eloquent-relationships#polymorphic-relations

Categories