Laravel Constraining Eager Loading all table data - laravel

I have two model News and Category in one to many relationship.
News.php
public function newsCategory()
{
return $this->belongsTo(Category::class, 'category');
}
Now I'm trying to get all the news with a specific category as follows
$news = News::select('id', 'heading', 'body', 'image', 'category', 'created_at')
->with(['newsCategory' => function ($query) {
$query->where('title', 'international');
}])->get();
dd($t->toArray());
But its printing all the news, as follows
Laravel version : 7.30
Doc ref: https://laravel.com/docs/7.x/eloquent-relationships#constraining-eager-loads

Use whereHas
$news = News::select('id', 'heading', 'body', 'image', 'category', 'created_at')
->with(['newsCategory'])
->whereHas('newsCategory',function ( $query){
$query->where('title', 'international');
})
->get();
Ref: https://laravel.com/docs/7.x/eloquent-relationships#querying-relationship-existence

Related

Why might the Elequent ORM relationship feel empty?

Here is my method available in the controller
public function getProductListAll(){
$products = Product::with('property')
->whereStatus(1)
->where('show', 1)
->where('code', '!=', 1)
->where('is_roketable',true)
->with(['prices_roket' => function ($q) {
return $q->whereNull('user_id');
}]);
$products = $products->whereIn('product_type', ['education', 'consultancy', 'startup']);
$data['products'] = $products->select([
'id', 'name', 'image', 'commission', 'price',
'buy_now', 'type', 'short_desc', 'pricing_desc',
'offer_status', 'period_status', 'period', 'period_frequency',
'endpoint', 'product_type', 'unique_id', 'discount_show_status',
'annual_payment', 'pre_register', 'privacy_status', 'privacy',
'sg_project', 'last_pre_register_date', 'product_desc',
'product_consulting', 'product_status',
])->get();
return response()->json($data);
}
and here is the relationship in my model.
return $this->hasMany(ProductPrice::class)->select('price','created_at','user_id','offer_id')
->orderBy('price')
->where(function ($q) {
$q
->where(function ($q2) {
$q2->whereNull('offer_id');
})
->orWhere(function ($q2) {
$q2->whereNotNull('offer_id');
$q2->where('user_id', auth()->user() ? auth()->user()->id : 0);
});
});
I tried to change my relationship and rewrite it, but when I write select, I cannot access any data. When I remove select, they all come. I can't select at prices relationship.
You can not use ->select() inside your model relationship.
Instead what you can do to limit the selection is by adding it into ->with()
For example
$products = Product::query()
->with(['property' => function ($q) {
$q->select(['price','property.created_at','user_id','offer_id']);
}])
->where( ... )
// no need to add property 'price' inside this select
->select(['id', 'name', 'image', 'commission' ... ])
->get();

output category with child categories and posts and pagination

I want to get category with all children subcategories and posts where id = category_id.
Posts should be paginated.
In category model I have 2 relations.
public function children() {
return $this->hasMany(self::class, 'parent_id');
}
public function posts() {
return $this->hasMany(Post::class, 'category_id');
}
In controller I have this function
public function getCategoryWithPaginatedPosts($slug, $perPage = null)
{
$columns = ['id', 'parent_id', 'title', 'slug', 'description', 'image'];
$postsColumns = ['category_id','title','text'];
$result = Category::whereSlug($slug)
->select($columns)
->with('children')
->with(['items' => function ($q) use ($postColumns) {
$q->wherePublished(true)
->select($postColumns)
->orderBy('id', 'ASC')
->paginate();
}])
->first();
}
Pagination doesn't work.
I just see that number of items is equal to $perPage parameter (and I have more items), but I don't see paginator inside dd($result->items)
It works like that, though I believe it is not the best way to do that.
So I can do it in few steps.
In first step I retrieve all data from DB and convert models to array, because I don't need models on webpage and I suppose it works faster like that. I would use ->toBase() if it could take mutators and relations from the model.
Second step I convert array into stdClass, because it is more comfortable in blade to work with object rather than with array.
Third step is to paginate items with mypaginate function (manual paginator in AppService Provider).
public function getCategoryWithPaginatedPosts($slug, $perPage = null)
{
$columns = ['id', 'parent_id', 'title', 'slug', 'description', 'image'];
$postsColumns = ['category_id','title','text'];
$result = Category::whereSlug($slug)
->select($columns)
->with('children')
->with(['items' => function ($q) use ($postColumns) {
$q->wherePublished(true)
->select($postColumns)
->orderBy('id', 'ASC');
}])
->first()
->toArray();
$result = Arr::arrayToObject($result);
$result->items = collect($result->items)->mypaginate($perPage);
return $result;
}
you should not use ->first() after ->paginate(), change something like this,
$result = Category::whereSlug($slug)
->select($columns)
->with('children')
->with(['items' => function ($q) use ($postColumns) {
$q->wherePublished(true)
->select($postColumns)
->orderBy('id', 'ASC')
}])
->paginate(20);

Laravel 8 eager loading, how to access subquery fields

This is working:
$clients = Client::with([
'contacts' => function ($query) {
$query
->select('client_id', 'first_name', 'last_name')
->where('contact_type_id', '=', 1);
}])
->orderBy('client_name')
->get(['id', 'client_name', 'city', 'state']);
dd($clients);
However, I'm unsure of how to access first_name and last_name on the subquery. They're showing up in the "relations" object in the dump, but in my mind I'm envisioning a dataset that I would access like,
$client->first_name, etc.
When I try to add the fields to the get() method at the end, it doesn't recognize them, so I'm doing something wrong, or I need to access the subquery fields differently.
When you are eager loading the relationships, you are just preloading them.
If your relationship is defined as hasMany (which seems to be the case here, a Client hasMany Contact), then you'll always get a collection from eager loading.
If you defined another relationship in your model in order to get only one result, for instance:
public function contact()
{
return $this->hasOne(Contact::class)->where('contact_type_id', 1)->latest('id');
}
Your new relationship contact would return only one result:
$clients = Client::with('contact')
->orderBy('client_name')
->get(['id', 'client_name', 'city', 'state']);
foreach($clients as $client){
dd($client->contact->first_name);
}
// each Client of $clients would have a ->contact relationship
You should add field id to select() method in subquery and field contact_id to get() method
$clients = Client::with(['contacts' => function ($query) {
$query->select('id', 'client_id', 'first_name', 'last_name')->where('contact_type_id', '=', 1);
}])
->orderBy('client_name')
->get(['id', 'client_name', 'city', 'state', 'contact_id']);
foreach ($clients as $key => $client) {
dd($client->contacts->first_name);
// Or
dd($client->contacts()->first()->first_name);
}

Created_at time are all same table relation in Laravel6

I'm studying table relation in Laravel6. Here is my code which works but suddenly all records Created_at time displayed the same 2021-08-02 11:34:30. I'm sure that time was right. but I noticed it all same. Could you teach me how to fix please?
I would like to get the products table's created_at.
class ProductController extends Controller {
public function index() {
$products = Product::All();
$products = Product::with('categori')
->join('creators', 'creators.id', '=', 'products.creator_id')
->join('categoris', 'categoris.id', '=', 'products.categori_id')
->join('branches', 'branches.id', '=', 'products.br_id')
->join('users', 'users.id', '=', 'products.user_id')
->join('colors', 'colors.id', '=', 'products.color_id')
->get();
$data = array(
'title' => 'index',
'no' => 1,
'products' => $products,
'created_at' => created_at,
);
return view('product.index',$data);
}
Here is my blade file
{{ $product->created_at->format('Y-m-d H:i:s') }}
UPDATE: Model Produt
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
protected $fillable = ['title','kansu', 'customer', 'memo', 'status', 'memo2', 'color_id', 'creator_id', 'br_id','user_id' ,'categori_id'];
public function categori()
{
return $this->belongsTo(Categori::class);
}
}
Produts Table image
I'm not familiar with format() method. You could try to use PHP date_format() to see if there is any difference.
#Bladeview:
{{ date_format($product->created_at, 'Y-m-d H:i:s') }}
Related docs: https://www.php.net/manual/en/datetime.format.php

How to Join tables in laravel with a value from previously joined table?

I have a table in laravel which tracks recent views of posts by users. Here is its controller
$contents = RecentView::where('user_id', $loggedUser)
->with('posts.user')
->with(['posts.note' => function($query) use($loggedUser){
$query->where('user_id', $loggedUser);
}])
->with(['posts.tags' => function($query) use($loggedUser){
$query->where('user_id', $loggedUser);
}])
->with(['posts.savedpost' => function($query) use($loggedUser){
$query->where('user_id', $loggedUser);
}])
->with(['following' => function($query) use($loggedUser){
$query->where('user_id', $loggedUser)
->where('follower_id', 'id');
}])
->paginate(12)->toArray();
I always gel blank values in 'following'. i want to join 'follow' table using 'user_id' field from 'posts' table.
my model is as follows:
public function posts()
{
return $this->hasOne('App\FeedPost', 'id', 'post_id');
}
public function following()
{
return $this->hasOne('App\Follow');
}
can someone tell me how i can do this?

Resources