Laravel: Paginate query which is ordered by a hasOne-relationship - php

I have a Customer model which has many Contacts. I want to create a view / list of contacts which paginated and ordered by the latest Contact.
Customer.php
public function contacts()
{
return $this->hasMany(Contact::class);
}
public function latestContact()
{
return $this->hasOne(Contact::class)->latestOfMany()->withDefault();
}
In the view, I want to show the customers like this:
#foreach ($customers as $customer)
<x-table.row wire:key="row-{{ $customer->id }}">
<x-table.cell>
{{ $customer->last_name }}, {{ $customer->first_name }}
</x-table.cell>
<x-table.cell>
{{ $customer->latestContact->contacted_at }}
</x-table.cell>
</x-table.row>
#endforeach
Table Structure
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id');
$table->string('first_name');
$table->string('last_name');
});
Schema::create('contacts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id');
$table->foreignId('customer_id');
$table->string('type');
$table->string('body');
$table->timestamp('contacted_at');
});
I am struggling to get the correct query for this. Here's my last try which gives me the following error:
Illuminate\Database\QueryException
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'latestContact.contacted_at' in 'order clause'...
return view('livewire.dashboard', [
'customers' => Customer::with('customers.*', 'latestContact.contacted_at')
->join('contacts', 'contacts.customer_id', '=', 'customers.id')
->orderBy('latestContact.contacted_at')
->paginate(25)
]);
Appreciate your support!

I think you should rewrite your query like this
Customer::with(['contacts', 'latestContact'])
->orderBy('latestContact.contacted_at')
->paginate(25)
Updated Answer
$customers= Customer::with(['contacts', 'latestContact'=>function($query){
return $query->orderBy('contacted_at','DESC');
}])->paginate(25);
In Customer model you need to modify relation like below
public function latestContact()
{
return $this->hasOne(Contact::class)->withDefault();
}
latestOfMany Indicate that the relation is the latest single result of a larger one-to-many relationship.
latestOfMany($column = 'id', $relation = null)

Related

Laravel 8: Base table or view not found

I have two tables at db, one of them is named users which simply contains user information of website and the other one is tags which contains some hashtags that users can choose from them.
I also created a table named tag_user that can store the tag_id and user_id like this image:
(just like Stackoverflow that a user can select multiple tags such as php, javascript & etc)
So in order to make this relationship between these two, I added this to User model:
public function tags()
{
return $this->belongsToMany(User::class);
}
And also this one to Tag model:
public function users()
{
return $this->belongsToMany(Tag::class);
}
And here is the select option on blade, and users can select multiple tags from db:
<select class="form-control BSinaBold" name="skills[]" id="skills" multiple>
#foreach(\App\Models\Tag::all() as $tag)
<option value="{{ $tag->id }}" {{ in_array($tag->id , Auth::user()->tags->pluck('id')->toArray()) ? 'selected' : '' }}>{{ $tag->name }}</option>
#endforeach
</select>
Now as soon as I load the blade, I got this as error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'dbname.user_user' doesn't exist (SQL: select users.*, user_user.user_id as pivot_user_id from users inner join user_user on users.id = user_user.user_id where user_user.user_id = 4)
So what's going wrong here? How can I fix this issue?
I would really appreciate any idea or suggestion from you guys...
And here is also the migration of tags & tag_user table:
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('label');
$table->timestamps();
});
Schema::create('tag_user', function (Blueprint $table) {
$table->unsignedBigInteger('tag_id');
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->primary(['tag_id','user_id']);
});
}
Thanks in advance.
As #aynber described in the comments:
In User model
public function tags()
{
return $this->belongsToMany(Tag::class);
}
And in Tag model
public function users()
{
return $this->belongsToMany(User::class);
}

How to use hasOne relationship correctly?

I am learning Laravel and I'm trying to create simple online store.
I created tables Items and Amounts. Now I want to display all Items with their amount in stock but for some reason unknown to me, amount of item is not fetched into items.
These are my schemas for tables:
Items:
Schema::create('items', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->string('name', 120)->nullable(false);
$table->float('price',8,2)->unsigned()->nullable(false);
$table->longText('short_specification');
$table->longText('specification');
$table->longText('description');
$table->string('photo', 100);
$table->engine = 'InnoDB';
$table->foreign('category_id')->references('id')->on('categories');
});
Amounts:
Schema::create('amounts', function (Blueprint $table) {
$table->integer('item_id')->unsigned();
$table->integer('amount')->unsigned()->nullable(false);
$table->engine = 'InnoDB';
});
Schema::table('amounts',function($table){
$table->foreign('item_id')->references('id')->on('items');
$table->primary('item_id');
});
These are my models:
Item:
class Item extends Model
{
public $timestamps = false;
function amount()
{
return $this->hasOne('App\Amount','item_id','id');
}
}
Amount:
class Amount extends Model
{
function item()
{
//$this->belongsTo('App\Item');
return $this->belongsTo('App\Item','item_id','id');
}
}
When I do:
$items = DB::table('items')->get();
dd($items);
return view('home')->with('items',$items);
Items are displayed correctly, but amount of item isn't there.
When I do:
#foreach($items as $item)
{{ $item->id }}
{{ $item->amount }}
#endforeach
I get:
Undefined property: stdClass::$amount (View: D:\2.
PROGRAMY\xampp\htdocs\silicon_store\resources\views\home.blade.php)
error.
From what I've seen on the web (I've been trying to fix this for over 3 hours now so I must be doing something totally wrong) it should work properly but it isn't.
With $items = DB::table('items')->get();, you're using the query builder. It won't have the value of the relationship unless you join the amounts table in the query.
$items = DB::table('items')
->leftJoin('amounts', 'items.id', '=', 'amounts.item_id')
->get();
I think you could also use an Eloquent query. In that case each $item would be an instance of the Item model rather than a StdClass object.
$items = App\Item::with('amount')->get();
or you can use kind of this query
$items = App\Item::whereHas('amount')->get()
Here link to understanding whereHas

Join using associatif table

I set up a relationship between the following three tables : Card, Event and Presence (associatif table). Presence my associatif table, which contains id_card and id_event. I tried to create a fuction that return $count (number of event foreach member).
But my problem is $count return if the number of all event or zero and the result have been 1
My controller :
$count = DB::table('presences')
->join('cards','cards.id','presences.id_card')
->join('events','events.id','presences.id_event')
->where('presences.date','like','%event.dateEvent%')
->where('presences.qrcode','like','%cards.qrcode_membre%')
->get()
->count();
Model Card :
public function event()
{
return $this->belongsToMany('App\Event');
}
Migration :
$table->bigIncrements('id');
$table->string('nom');
$table->string('prenom');
$table->string('cin');
$table->date('dateNaissance');
$table->date('dateAffection');
$table->string('qrcode_membre')
Model Event :
public function card()
{
return $this->belongsToMany('App\Card');
}
Migration :
$table->bigIncrements('id');
$table->string('libelle');
$table->string('description');
$table->date('dateEvent');
Model Presence :
$table->bigIncrements('id');
$table->date('heureEntree');
$table->date('heureSortir');
$table->date('date');
$table->string('qrcode');
$table->unsignedInteger('id_card');
$table->foreign('id_card')->references('id')->on('cards');
$table->unsignedInteger('id_event');
$table->foreign('id_event')->references('id')->on('events');

Column not found: 1054 Unknown column 'id' in 'where clause' - Laravel

There has been lot of issues on this but i am following the exact procedure to solve this issue as described in the other related S.O questions yet i get the same error.
Shop
public function products()
{
return $this->hasMany('App\Product');
//->withTimestamps();
}
Product
public function shop()
{
return $this->belongsTo('App\Shop');
//->withTimestamps();
}
This is how my schema looks like
Schema::create('products', function (Blueprint $table) {
$table->increments('product_id');
$table->integer('shop_id')->unsigned()->nullable();
$table->foreign('shop_id')->references('id')->on('shops');
$table->timestamps();
);
Controller
$products = new Product(array(
'name' => $request->('name');
));
$shop->products()->save($products);
After submitting my form data into the products table, i get an error Column not found: 1054 Unknown column 'id' in 'where clause'. Laravel by default seems to take id by default as my primary key but then it is product_id.
In my model, i have specified protected $primaryKey = 'product_id' and it wouldn't solve my problem. What am i doing differently ?
In the relationships you have to specify the name of the primary key when it is not called id, try to change the model like this:
SHOP
public function products()
{
return $this->hasMany('App\Product', 'product_id');
//->withTimestamps();
}
PRODUCT
public function shop()
{
return $this->belongsTo('App\Shop', 'product_id');
//->withTimestamps();
}
In the documentation explains how it works:
https://laravel.com/docs/5.5/eloquent-relationships#one-to-many
If you are using resoure routes, then you need to specify the route key name as well:
public function getRouteKeyName()
{
return 'product_id';
}
I had tried with my local with following:
Schema:
Schema::create('shops', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('products', function (Blueprint $table) {
$table->increments('product_id');
$table->string('name');
$table->integer('shop_id')->unsigned()->nullable();
$table->foreign('shop_id')->references('id')->on('shops');
$table->timestamps();
});
Model relationship exactly same as your post.
Controller code:
$shop = new Shop;
$shop->name = 'test';
$shop->save();
$products = new Product;
$products->name = 'test';
$shop->products()->save($products);
And final result? It is saved into products table without error.
I am using Laravel 5.4 at my local.
When it stated Unknown column 'id' in 'where clause' but does it stated is products table? Can you show the full Sql error log?
I suspect it might be other relationship caused the error.

Integrity constraint violation: 1062 Duplicate entry '25' for key 'PRIMARY'

I want to add multiple tags in mysql database table , in this case when try to add single tag then it's alright but when try to insert multiple tags show this types of error . Here is my migration and storing code .
public function store(CreateArticleRequest $request)
{
$article = Auth::user()->articles()->create($request->all());
$article->tags()->attach($request->input('tags'));
flash()->overlay('Your articles has been created!', 'Good Job');
return redirect('articles');
}
Here is migration code :
public function up()
{
Schema::create('tags',function(Blueprint $table){
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('articles_tag',function(Blueprint $table) {
$table->increments('articles_id')->unsigned()->index();
$table->foreign('articles_id')->references('id')->on('articles')->onDelete('cascade');
$table->integer('tag_id')->unsigned()->index();
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
$table->timestamps();
});
}
Here is Form code Tag selecting box for in blade :
<div class="form-group">
{!! Form::label('tags','Tags:') !!}
{!! Form::select('tags[]',$tags,null,['class'=>'form- control','multiple']) !!}
Your migration is wrong. The table articles_tag is a pivot table, so you can't use increments for the articles_id column in that table.
To solve this, replace this line:
$table->increments('articles_id')->unsigned()->index();
with this one:
$table->integer('articles_id')->unsigned()->index();

Categories