how to insert one product to many categoies laravel attach() - php

I have tried much time but failed.
Ex: I want result like if I insert a Product into the database and select multiple categories and store them different table then show me error like this:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'space.category_product' doesn't exist (SQL: insert into `category_product` (`category_id`, `product_id`) values (1, ))
If I rename database table From category_products To category_product manually the show me a new Error here below :
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'product_id' cannot be null (SQL: insert into `category_product` (`category_id`, `product_id`) values (1, ))
Here is my Database Code
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('model');
$table->string('slug')->unique();
$table->string('availability');
$table->float('price');
$table->longText('images');
$table->text('short_detail');
$table->text('feature');
$table->longText('purchase_delivery');
$table->longText('replace_policy');
$table->timestamps();
});
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('slug');
$table->timestamps();
});
Schema::create('category_products', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products')->onUpdate('cascade')->onDelete('cascade');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');
$table->timestamps();
});
Here is My Models:
class Category extends Model
{
public function Products()
{
return $this->belongsToMany(Product::class);
}
}
class Product extends Model
{
public function Categories()
{
return $this->belongsToMany(Category::class);
}
}
ProductController:
public function store(Request $request)
{
if ($request->hasFile('file')){
foreach ($request->file as $file) {
$fileExt = $file->getClientOriginalExtension();
$uniqId = uniqid('img-');
$fileName[] =$uniqId.'.'.$fileExt;
$Name = $uniqId.'.'.$fileExt;
$file->move('public/uploads',$Name);
}
$images = implode(",",$fileName);
$product = new Product();
$product->Categories()->attach($request->categories_id);
$product->name= $request->input('name');
$product->model= $request->input('model');
$product->slug= $request->input('slug');
$product->availability= $request->input('availability');
$product->price= $request->input('price');
$product->images= $images;
$product->short_detail= $request->input('short_detail');
$product->feature= $request->input('feature');
$product->purchase_delivery= $request->input('purchase_delivery');
$product->replace_policy= $request->input('replace_policy');
if ($product->save()) {
return redirect()->route('product.index')
->with('success', 'Product Added successfully');
}
return back()->withInput()->with('errors', 'Error Adding New Product');
}
}

Schema::create('category_product', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products')->onUpdate('cascade')->onDelete('cascade');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');
$table->timestamps();
});
You have typo in the name it should be category_product.
Your table name should be alphabetically ordered and use singular names.
If you do not want to change the table names
public function Categories()
{
return $this->belongsToMany(Category::class, 'category_products,'category_id', 'product_id');
}
My ProductController :
public function store(Request $request)
{
if ($request->hasFile('file')){
foreach ($request->file as $file) {
$fileExt = $file->getClientOriginalExtension();
$uniqId = uniqid('img-');
$fileName[] =$uniqId.'.'.$fileExt;
$Name = $uniqId.'.'.$fileExt;
$file->move('public/uploads',$Name);
}
$images = implode(",",$fileName);
$product = new Product();
$product->name= $request->input('name');
$product->model= $request->input('model');
$product->slug= $request->input('slug');
$product->availability= $request->input('availability');
$product->price= $request->input('price');
$product->images= $images;
$product->short_detail= $request->input('short_detail');
$product->feature= $request->input('feature');
$product->purchase_delivery= $request->input('purchase_delivery');
$product->replace_policy= $request->input('replace_policy');
$product->save();
$product->Categories()->attach($request->categories_id);
if ($product->save()) {
return redirect()->route('product.index')
->with('success', 'Product Added successfully');
}
return back()->withInput()->with('errors', 'Error Adding New Product');
}
}
Use $product->categories()->attach($category_id) after the $product->save()

Here you can use your models
class Category extends Model
{
public function Products()
{
return $this->belongsToMany(Product::class, 'category_products');
}
}
class Product extends Model
{
public function Categories()
{
return $this->belongsToMany(Category::class, 'category_products);
}
}
Here category_products is a pivot table.
Now Save
$product = Product::create(['name' => 'product1']);
$product->Categories()->sync([1, 3, 4]);
OR
$product->Categories()->attach([1, 3, 4]);
Difference
Sync: You may also use the sync method to construct many-to-many associations. The sync method accepts an array of IDs to place on the
intermediate table. Any IDs that are not in the given array will be
removed from the intermediate table. So, after this operation is
complete, only the IDs in the given array will exist in the
intermediate table:
Attach: It is same like append, it append the new values with the existing one

Related

Booking system with many to many laravel relationship

I'm trying to make an app where airbnb hosts can have a log of their bookings, I created three models: Home, Guest and Booking. Booking being the main player, I also think there should be a pivot table but I'm not sure which models should it link... I decided to go with booking_guest but I'm getting the following error when I create a booking:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'booking_id' cannot be null (SQL: insert into `booking_guest` (`booking_id`, `guest_id`) values (?, 1), (?, 2))
I do something like this in my BookingController:
public function create(Request $request)
{
$guestIds = Guest::latest()->take(2)->pluck('id');
$home = Home::findOrFail(1);
$booking = new Booking();
$booking->home_id = $home->id;
$booking->guests()->attach($guestIds);
$booking->save();
return response()->json([
'booking' => $booking,
]);
}
I'm not feeling too sure about this configuration, could you guys share some light on me.
These are my models:
class Home extends Model
{
public function guests()
{
return $this->belongsToMany('App\Models\Guest', 'guest_home', 'home_id', 'guest_id');
}
public function bookings()
{
return $this->hasMany('App\Models\Booking');
}
}
class Booking extends Model
{
public function guests()
{
return $this->belongsToMany('App\Models\Guest', 'booking_guest', 'booking_id', 'guest_id');
}
}
class Guest extends Model
{
public function bookings()
{
return $this->belongsToMany('App\Models\Booking', 'booking_guest', 'guest_id', 'booking_id');
}
}
My migrations:
//Booking guest pivot table
Schema::create('booking_guest', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('booking_id')->index();
$table->foreign('booking_id')->references('id')->on('bookings')->onDelete('cascade')->onUpdate('cascade');
$table->unsignedInteger('guest_id')->nullable()->index();
$table->foreign('guest_id')->references('id')->on('guests')->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
Schema::create('guests', function (Blueprint $table) {
$table->increments('id');
$table->string('fullName');
$table->text('country');
$table->timestamps();
});
Schema::create('bookings', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('home_id')->index();
$table->foreign('home_id')->references('id')->on('homes')->onDelete('cascade')->onUpdate('cascade');
$table->timestamp('entryDate')->nullable();
$table->timestamp('exitDate')->nullable();
$table->timestamps();
});
Schema::create('homes', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('host_id')->index();
$table->foreign('host_id')->references('id')->on('hosts')->onDelete('cascade')->onUpdate('cascade');
$table->string('fullAddress')->unique();
$table->integer('rooms')->unique();
$table->timestamps();
});
As you can see from here:
public function create(Request $request)
{
...
$booking = new Booking(); // <-- here
$booking->guests()->attach($guestIds); // <-- here
$booking->save(); // <-- here
...
}
you are creating a new instance of Booking, then associating to it a Guest and then saving the instance of Booking.
However ->attach(...) tries to associate the Booking with the Guest, but the Booking does not exists at that time on the DB.
I would suggest to use Booking::create, so that after that statement, the booking exists on the DB and so you can attach to it the Guest:
public function create(Request $request)
{
$guestIds = Guest::latest()->take(2)->pluck('id');
$home = Home::findOrFail(1);
$booking = Booking::create([ // <- using Booking::create
'home_id' => $home->id // <- using Booking::create
]); // <- using Booking::create
$booking->guests()->attach($guestIds);
return response()->json([
'booking' => $booking,
]);
}

Property [products] does not exist on this collection instance

in my app I first retrieve product categories with products, now I want to extract products from product categories but I get the following error:
Property [products] does not exist on this collection instance.
This is how I get categories first and then products
$productCategories = ProductCategory::with('products')->get(); //This works
$products = $productCategories->products; //Then this gives me error
Here are my models and migrations:
class Product extends FilterableModel
{
protected $table = 'products';
public function category()
{
return $this->belongsTo('App\Models\ProductCategory', 'productcategory_id');
}
class ProductCategory extends FilterableModel
{
protected $table = 'productcategories';
public function products()
{
return $this->HasMany('App\Models\Product', 'productcategory_id');
}
}
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('productcategory_id')->index();
$table->foreign('productcategory_id')->references('id')->on('productcategories')->onDelete('cascade')->onUpdate('cascade');
$table->string('title');
$table->string('slug');
$table->string('url');
$table->text('body')->nullable();
$table->string('image')->nullable();
$table->boolean('isVisible')->default(false);
$table->boolean('isFeatured')->default(false);
$table->integer('stock')->default(0);
$table->decimal('originalPrice', 5,2)->default(0.00);
$table->decimal('finalPrice', 5,2)->default(0.00);
$table->timestamps();
});
Schema::create('productcategories', function (Blueprint $table) {
$table->increments('id');
$table->string('title')->unique();
$table->string('slug')->unique();
$table->string('url')->unique();
$table->text('body')->nullable();
$table->string('image')->default(config('app.defaultImage'));
$table->string('icon')->default('fa fa-tag');
$table->boolean('isVisible')->default(false);
$table->boolean('isFeatured')->default(false);
$table->timestamps();
});
So, your $productCategories variable is a Collection of ProductCategory instances.
If you want to get a products of all of them, you need to loopin it:
foreach ($productCategories as $productCategory) {
dump($productCategory->products);
}
If you want to get products of one of productCategory you need to select it from database:
$productCategory = ProductCategory::findOrFail($productCategoryId);
dump($productCategory->products);
Hope it helps.

Can I create custom pivot table name using another M:M entity?

I'm still thinking is there a ways how can I create a custom pivot table name? Because I created a documents and users table has a many to many relationship with document_user which is my pivot table and this table was created for received document that user created. And I'm planning to create a another pivot table for document and user this table was for sent documents so I can have history. See my code below.
create_document_user_table
public function up()
{
Schema::create('document_user',function (Blueprint $table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('document_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('document_id')->references('id')->on('documents')->onDelete('cascade');
$table->unsignedInteger('sender_id')->nullable();
$table->foreign('sender_id')->references('id')->on('users')->onDelete('cascade');
$table->dateTime('dateReceived')->default(DB::raw('CURRENT_TIMESTAMP'));
$table->timestamp('dateModified')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
});
}
documents_table
public function up()
{
Schema::create('documents', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('content');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->timestamps();
});
}
users_table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('first_name');
$table->string('last_name');
$table->string('middle_name');
$table->string('email');
$table->string('username');
$table->string('address');
$table->string('password');
$table->string('remember_token');
$table->integer('role_permission_id')->unsigned();
$table->foreign('role_permission_id')->references('id')->on('roles_permissions_dt')->onDelete('cascade');
$table->timestamps();
});
}
This works well inserting records to my pivot table. What I'm planning to achieve is every-time I inserted a records for documents this will inserted too in my custom pivot table not only in my document_user pivot table. Any help would appreciated! Thanks for your info or tips.
UPDATE
#Mina thanks for the tips that you given but actually this is my insert or save for my pivot table. How can I inserted this in my revisions table?
DocumentController
public function postDocuments(Request $request)
{
$this->validate($request,
[
'title' => 'required|regex:/(^[A-Za-z0-9 ]+$)+/|max:255',
'content' => 'required',
'category_id' => 'required',
'recipient_id' => 'required',
]);
$document = new Document();
//Request in the form
$document->title = $request->title;
$document->content = $request->content;
$document->category_id = $request->category_id;
$document->save();
$user = Auth::user();
foreach($request->recipient_id as $recipientId)
{
$document->recipients()->sync([ $recipientId => ['sender_id' => $user->id]],false );
}
return redirect()->back();
}
You can call your pivot tables as you like.
As mentioned previously, to determine the table name of the
relationship's joining table, Eloquent will join the two related model
names in alphabetical order. However, you are free to override this
convention. You may do so by passing a second argument to the
belongsToMany method:
return $this->belongsToMany('App\Role', 'user_roles');
(Eloquent: Relationships #Many To Many)
In your case you would need to define the relations like this:
class User extends Model
{
// other stuff
createdDocuments()
{
return $this->belongsToMany('App\Document', 'document_user_created');
}
sentDocuments() // or receivedDocuments()
{
return $this->belongsToMany('App\Document', 'document_user_sent');
}
// other stuff
}
class Document extends Model
{
// other stuff
createdByUsers()
{
return $this->belongsToMany('App\User', 'document_user_created');
}
sentToUsers() // or sentFromUsers() or whatever it does mean
{
return $this->belongsToMany('App\User', 'document_user_sent');
}
// other stuff
}
You do not need another pivot table. You need a table like that:
public function up()
{
Schema::create('revisions', function (Blueprint $table) {
$table->increments('id');
$table->integer('document_id')->unsigned();
//Rest of table structure
$table->foreign('document_id')->references('id')->on('document_user')->onDelete('cascade');
$table->timestamps();
});
}
When you need to create a new Revision:
$document = new Document;
//add $document attributes
$user->documents()->save($document);
$document->recipients->each(function($recipient){
$id = $recipient->pivot->id;
Revision::create(['document_id'=>$id]);
})

Laravel 5.2 - Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

This question has already been asked many times, I went through all the answers, but none solves the error I'm getting.
I'm using Laravel 5.2
I have 2 tables - Classifieds and Categories. When I want to create a classified, I get the error message:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (myclassified.classifieds, CONSTRAINT classifieds_category_id_foreign FOREIGN KEY (category_id) REFERENCES categories (id))
Migration files defined like this:
for classifieds table:
public function up()
{
Schema::create('classifieds', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('description');
$table->string('price');
$table->timestamps();
});
}
public function down()
{
Schema::drop('classifieds');
}
for categories table:
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::drop('categories');
}
and to add the foreign key,
public function up()
{
Schema::table('classifieds', function(Blueprint $table) {
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories');
});
}
public function down()
{
Schema::table('classifieds', function(Blueprint $table) {
$table->dropForeign('classifieds_category_id_foreign');
});
}
The Models are:
Classified model:
class Classified extends Model
{
protected $table = 'classifieds';
protected $fillable = ['title', 'category_id', 'description', 'price'];
protected $hidden = [];
public function category(){
return $this->belongsTo('App\Category');
}
}
and the Category model:
class Category extends Model
{
protected $table = 'categories';
protected $fillable = ['name'];
protected $hidden = [];
public function classifieds(){
return $this->hasMany('App\Classified');
}
}
and the store method in controller is defined like this:
public function store(Request $request)
{
$title = $request->input('title');
$category_id = $request->input('category_id');
$description = $request->input('description');
$price = $request->input('price');
Classified::create([
'title' => $this->title,
'category_id' => $this->category_id,
'description' => $this->description,
'price' => $this->price
]);
return \Redirect::route('classifieds.index')
->with('message', 'Ad created');
}
What is my mistake in database set up?
This happens, when you are trying to save Classified and assign the foreign key with an id of category that does not exist yet in Category table.
If you don't have the foreign ID yet, just leave it to be null and make sure you do this on migration to allow null values;
public function up()
{
Schema::table('classifieds', function(Blueprint $table) {
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('set null');
});
}
public function down()
{
Schema::table('classifieds', function(Blueprint $table) {
$table->dropForeign('classifieds_category_id_foreign');
});
}

How to get all items with a certain property in pivot table with eloquent?

I have a 'favourite' functionality for my loops table. I am trying to achieve this with a pivot table. But now I'm trying to find the most efficient way to call all the logged in users favourited loops with eloquent.
loops table :
Schema::create('loops', function(Blueprint $table) {
$table->increments('id');
$table->string('name', 35);
$table->string('loop_path', 255);
$table->string('FK_user_id');
});
users table:
Schema::create('users', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('password', 60);
});
favourites table :
Schema::create('favourites', function(Blueprint $table) {
$table->increments('id');
$table->integer('FK_user_id')->unsigned();
$table->integer('FK_loop_id')->unsigned();
});
Loop.php :
class Loop extends Model {
protected $table = 'loops';
public $timestamps = true;
public function user()
{
return $this->belongsTo('App\User','FK_user_id','id');
}
public function favourites()
{
return $this->belongsToMany('App\User', 'favourites', 'FK_loop_id', 'FK_user_id');
}
}
This is how I achieve this now , but it doesn't seem efficient :
$loops = Loop::with('favourites')->
with('user')->get();
$favouritedLoops = array();
foreach($loops as $loop)
{
//check if logged in user has favourited this
$user_favorites = Favourite::where('FK_user_id', '=', Auth::user()->id)
->where('FK_loop_id', '=', $loop->id)
->first();
if ($user_favorites != null)
{
array_push($favouritedLoops, $loop);
}
}
return Response::json($favouritedLoops);
You should define favouritedLoops method in User model, then You can easily access all favourited loops.
User.php
public function favouritedLoops()
{
return $this->belongsToMany('App\Loop', 'favourites', 'FK_user_id', 'FK_loop_id');
}
and return now will look like:
return Response::json(Auth::user()->favouritedLoops);

Categories