Laravel HasMany WhereNotIn Query - php

Problem: I'm trying to query a PeopleType to find all the courses where a person isn't associated.
I have 4 tables
People
PeopleTypes
Courses
People_Courses
PeopleType_Courses
I have the following relationships
PERSON MODEL
public function getPeopleType() {
return $this->belongsTo('App\PeopleType','type_id');
}
public function getCourses() {
return $this->belpngsToMany('App\Course','People_Courses','person_id','course_id');
}
PEOPLE_TYPE MODEL
public function getPeople() {
return $this->hasMany('App\Person','type_id');
}
public function getCourses() {
return $this->belpngsToMany('App\Course','PeopleType_Courses','people_type_id','course_id');
}
My attempt:
$peopleType = \App\PeopleType::FindOrFail(1);
$courses = $peopleType->getCourses()->whereNotIn('id', function($q) use($person) {
$q->select('course_id')
->from('People_Courses')
->where('person_id', $person->id);
})->get();
My response:
Integrity constraint violation: 1052 Column 'id' in IN/ALL/ANY
subquery is ambiguous
People Courses Table Schematic
Schema::create('People_Courses', function (Blueprint $table) {
$table->increments('id');
$table->integer('course_id');
$table->integer('person_id');
);
PeopleType_Courses Table Schematic
Schema::create('PeopleType_Courses', function (Blueprint $table) {
$table->increments('id');
$table->integer('course_id');
$table->integer('people_type_id');
);

When you're working on relations that have similar column name being selected in the query you need to resolve the ambiguity by specifying the table name with the column. e.g:
$peopleType->getCourses()->whereNotIn('courses.id', function($q)... //courses.id

Related

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'products.wishlist_id' in 'where clause'

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'products.wishlist_id' in 'where clause' (SQL: select * from products where products.wishlist_id = 1 and products.wishlist_id is not null and products.deleted_at is null)
In my controller >>>
public function index() {
$wishlist_items = Wishlist::where('user_id', Auth::user()->id)->get();
foreach($wishlist_items as $item) {
dd($item->getProducts()->get());
}
}
Wishlist.php >>>
public function getProducts() {
return $this->hasMany(Product::class);
}
Product.php >>>
public function getWishlist() {
return $this->belongsTo(Wishlist::class);
}
Migration table >>>
Schema::create('wishlists', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('product_id');
$table->unsignedBigInteger('user_id');
$table->timestamps();
$table->foreign('product_id')->references('id')->on('products');
$table->foreign('user_id')->references('id')->on('users');
});
The hasMany() function queries the table for a {model_name}_id column - In this case, wishlist_id. Your products table is missing a wishlist_id column and the relevant foreign key. I'd suggest taking a look at the Laravel Documentation on one-to-many relationships.
Your migration will need to include updates to the existing products table to add the column and foreign key:
Schema::table('products', function (Blueprint $table) {
$table->unsignedBigInteger('wishlist_id');
$table->foreign('wishlist_id')->references('id')->on('wishlists');
});
That said, are you sure you're looking for a one-to-many relationship here? A wishlist can have multiple products, and a product can be in multiple wishlists - A many-to-many relationship may be a better option.

How to do join in different names in Laravel?

I have two tables named users and buys:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name');
$table->string('last_name');
$table->string('referral_code')->nullable();
$table->integer('parent_id')->unsigned()->nullable();
$table->string('mobile')->unique();
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function up()
{
Schema::create('buys', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->bigInteger('product_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->timestamps();
});
}
I want to do a join on users.parent_id and buys.user_id. Here is my current query:
public function user ()
{
return $this->hasOne(User::class);
}
My query:
$users = Buy::all()->where('parent_id', auth()->user()->id)->latest()->paginate(25);
But my query throws this:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'parent_id' in 'where clause' (SQL: select count(*) as aggregate from buys where parent_id = 2)
Any idea how can I fix it?
When making the relationship, Laravel expects that the foreign key name will be the method name + _id in your case user_id which is okay for the local key, but the foreign key is not the id on the user table, so you need to tell Laravel that. So try this instead:
public function user ()
{
return $this->hasOne(User::class, 'parent_id', 'user_id');
}
-- EDIT after seeing your query
You are trying to use a column that does not exist on your buys model.
$users = Buy::with('user')->where('user_id', auth()->user()->id)->latest()->paginate(25);
It should be like
$users = Buy::where('user_id', auth()->user()->parent_id)->latest()->paginate(25);

Laravel 5.4 transaction and one-many relation

I just started laravel but I'm stuck to this point and I don't find a way to do it
Basically I insert an article with a category.
With select2, I select an existing category or I create a new one.
My article model :
public function category(){
return $this->belongsTo('App\Category');
}
My categories model :
public function articles(){
return $this->hasMany('App\Article');
}
My article migration :
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->longText('content')->nullable();
$table->timestamps();
});
}
My category migration :
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('nom')->unique();
});
Schema::table('articles', function(Blueprint $table){
$table->integer('category_id')->unsigned()->index();
});
And finally my controller function to store article (I want to use transaction) :
public function store(Request $request)
{
$this->validate($request, [
'numero' => 'required',
'category' => 'required',
'title' => 'required'
]);
$article = new Article();
DB::transaction(function() use ($request) {
$category = Category::firstOrCreate(['nom' => $request->input('category')]);
$article->title = $request->input('title');
$article->save();
});
return response()->json([
'title' => $article->title
]);
}
So I know I don't save category id into article db but my category doesn't even insert, on my debug bar I've got this :
Begin Transaction
select * from batiments where (nom = 'HI') limit 1
Rollback Transaction
And my post page give me this error :
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicata du champ '' pour la clef 'batiments_nom_unique' (SQL: insert into batiments () values ())
Someone knpw how to insert or select if exist category and insert is id into article table ?
Thank
$table->integer('category_id')->unsigned()->index();
You set this field as index, just remove index(). Identity field must have only unique records, but your category_id may have same value many times.
code:
$table->integer('categorie_id')->unsigned();
$table->foreign('categorie_id')->references('id')->on('categories');
Laravel provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a categorie_id column on the articles table that references the id column on a categories table
laravel.com/docs/5.4/migrations#foreign-key-constraints

Where in pivot tables

I have next pivot table:
Schema::create('coach_user', function(Blueprint $table)
{
$table->integer('coach_id')->unsigned()->index();
$table->foreign('coach_id')->references('id')->on('coaches')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->tinyInteger('rank');
});
In User.php:
public function coaches()
{
return $this->belongsToMany(\App\Coach::class)->withPivot('rank');
}
How I can receive coaches of user with some rank? Something like this:
$user->coaches->where('rank',1)->get().
use wherePivot() to filter the results returned by belongsToMany.
$user->coaches()->wherePivot('rank',1)->get();
Use wherePivot for pivot columns and relation as method:
$user->coaches()->wherePivot('rank',1)->get().

Laravel 4.2 many to many relation, use something else then the default ID

I have 2 models and both they aren't using the ID from the table, but the field internal_id. So i customized my pivot schema but i got stuck on connecting them. Im getting the error:
General error: 1215 Cannot add foreign key constraint (SQL: alter table `seoshop_category_product` add constraint seoshop_category_product_category_id_foreign foreign key
(`category_id`) references `seoshop_categories` (`internal_id`) on delete cascade)
The code for the migration is:
Schema::create('seoshop_category_product', function(Blueprint $table)
{
$table->increments('id');
$table->integer('category_id')->unsigned()->index();
$table->foreign('category_id')->references('internal_id')->on('seoshop_categories')->onDelete('cascade');
$table->integer('product_id')->unsigned()->index();
$table->foreign('product_id')->references('internal_id')->on('seoshop_products')->onDelete('cascade');
$table->timestamps();
});
Both fields as seoshop_products.internal_id as seoshop_categories.internal_id are existing, column types are both int(11).
Can someone tell me what is going wrong?
Migrations for the tables seoshop_categories and seoshop_products
//seoshop_products
public function up()
{
Schema::create('seoshop_products', function(Blueprint $table)
{
$table->increments('id');
$table->integer('shop_id');
$table->integer('internal_id')->signed()->index();
$table->integer('internal_variant_id');
$table->string('visible');
$table->string('tags');
$table->timestamps();
});
}
//Table seoshop_categories
public function up()
{
Schema::create('seoshop_categories', function(Blueprint $table)
{
$table->increments('id');
$table->integer('internal_id')->signed()->index();
$table->datetime('seoshop_created_at');
$table->datetime('seoshop_updated_at');
$table->text('full_description');
$table->timestamps();
});
}
Okay so now i've create my table, and its working as how it should. I need to get my product with categories (many-2-many). So i use
SEOshopProduct::find(1)->with('categories')->get();
After a dd() the categories are empty and i've looked into my query how it is called:
[8] array(3) {
["query"] "select `seoshop_categories`.*, `seoshop_category_product`.`product_id` as `pivot_product_id`, `seoshop_category_product`.`category_id` as `pivot_category_id` from `seoshop_categories` inner join `seoshop_category_product` on `seoshop_categories`.`id` = `seoshop_category_product`.`category_id` where `seoshop_category_product`.`product_id` in (?)"
["bindings"] array(1) {
[0] 8
}
["time"] 0.37
}
The internal_id's of both products and categories is greater then 10.000 and i dont see it back in the query.
My models:
Product:
public function categories(){
return $this->belongsToMany('SEOshopCategory', 'seoshop_category_product', 'product_id', 'category_id');
}
Categories:
public function products(){
return $this->belongsToMany('SEOshopCategory', 'seoshop_category_product', 'category_id', 'product_id');
}
To setup the foreign key constraint, the field definitions need to match exactly. In this case, however, the seoshop_category_product.category_id field is defined as an UNSIGNED INT, but the referenced seoshop_categories.internal_id field is defined as a SIGNED INT. The same is true for the foreign key for your products.
So, you can either update the internal_id fields on your categories and products tables to be unsigned, or you can update your foreign key fields on your pivot table to be signed.
You can tell Laravel what the local and foreign keys are when you define the relationship in your model...
class Product extends Eloquent
{
public function categories() {
return $this->hasMany('Category', 'internal_id', 'id');
}
}
class Category extends Eloquent
{
public function products() {
return $this->hasMany('Product', 'internal_id', 'id');
}
}

Categories