Why might the Elequent ORM relationship feel empty? - laravel

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();

Related

Laravel one of many relationship with argument

coming from this relationship from the docs:
https://laravel.com/docs/9.x/eloquent-relationships#advanced-has-one-of-many-relationships
/**
* Get the current pricing for the product.
*/
public function currentPricing()
{
return $this->hasOne(Price::class)->ofMany([
'published_at' => 'max',
'id' => 'max',
], function ($query) {
$query->where('published_at', '<', now());
});
}
how can I make such an relation with a specific date?
The relation down below will work
/**
* Get pricing for the product of one specific date.
*/
public function priceOfDay(Carbon $date)
{
return $this->hasOne(Price::class)->ofMany([
'published_at' => 'max',
'id' => 'max',
], function ($query) {
$query->where('published_at', '<', $date());
});
}
but how can I use it with Eloquent? How can I pass the date to this:
Product::with('priceOfDay')->get();
update
I now use the one to many relation with a closure
->with(['prices' => function ($query) use ($month) {
$query->where('published_at', '<', $month)
->orderByDesc('published_at')
->orderByDesc('id')
->first();
}])
it works with the little drawback of having a collection instead of an object as relation, but it fills my needs for the moment.
It would be nice if there was something like
->with(['relation', $param])
update 2
since there seems to bo no direct solution here the workarround i came up with:
->first() does not work in the query, you will end up getting all prices, so I finished with an each()
->with(['prices' => function ($query) use ($month) {
$query->where('published_at', '<', $month)
->orderByDesc('published_at')
->orderByDesc('id');
}])
->get()
->each(function ($product) {
$product->price = $product->prices->first()->price;
})

How can I make this code easy . i use this query() function for many section

**
How can I make this code easy . i use this query() function for many section
i want to get event by filter. my filter based on tags and category(both are in pivot table)
**
public function index(Request $request)
{
$customQuery = Event::where('status', '1');
if ($request->vehical_type) { //vehical filter
$customQuery->where('vehical_type', '=', $request->vehical_type);
}
if ($request->tag) { //tag filter
$id = $request->tag;
$customQuery->whereHas('tags', function (Builder $query) use ($id) {
$query->where('tag_id', $id);
});
}
if ($request->category) { //category filter
$id = $request->category;
$customQuery->whereHas('categories', function (Builder $query) use ($id) {
$query->where('category_id', $id);
});
}
$events = $customQuery->get(); //get event according to filters
$tags = Tag::whereHas('events', function (Builder $query) { //get all tags of events
$query->where('event_id', '>', 0);
})->get();
$categories = Category::whereHas('events', function (Builder $query) { //get all categories of events
$query->where('event_id', '>', 0);
})->get();
return view('frontend.event.index', compact('events', 'tags', 'categories'));
}
You could use when for conditionals in the query and short hand closures with fn to put them in a single line.
whereRelation instead of whereHas could make those queries a bit shorter too.
public function index(Request $request)
{
$events = Event::query()
->where('status', '1')
->when(
$request->vehical_type,
fn($query) => $query->where('vehical_type', $request->vehical_type)
)
->when(
$request->tag,
fn($query) => $query->whereRelation('tags', 'tag_id', $request->tag)
// or fn($query) => $query->whereHas('tags', fn($tags) => $tags->where('tag_id', $request->tag))
)
->when(
$request->category,
fn($query) => $query->whereRelation('categories', 'category_id', $request->category)
// or fn($query) => $query->whereHas('categories', fn($category) => $category->where('category_id', $request->category))
)
->get();
$tags = Tag::query()
->whereRelation('events', 'event_id', '>', 0)
// or ->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
->get();
$categories = Category::query()
->whereRelation('events', 'event_id', '>', 0)
// or ->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
->get();
return view('frontend.event.index', compact('events', 'tags', 'categories'));
}
You could also maybe use a query scope to put the search in the Event model.
# Event.php
public function scopeSearch(Builder $query, array $filter = [])
{
return $query
->when(
array_key_exists('vehicle_type', $filter),
fn($query) => $query->where('vehical_type', $filter['vehicle_type'])
)
->when(
array_key_exists('tag', $filter),
fn($query) => $query->whereRelation('tags', 'tag_id', $filter['tag'])
// or fn($query) => $query->whereHas('tags', fn($tags) => $tags->where('tag_id', $filter['tag']))
)
->when(
array_key_exists('category', $filter),
fn($query) => $query->whereRelation('categories', 'category_id', $filter['category'])
// or fn($query) => $query->whereHas('categories', fn($category) => $category->where('category_id', $filter['category']))
);
}
public function index(Request $request)
{
$filter = [
'vehicle_type' => $request->vehicle_type,
'tag' => $request->tag,
'category' => $request->category,
];
$events = Event::query()
->where('status', '1')
->search($filter)
->get();
$tags = Tag::query()
->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
->get();
$categories = Category::query()
->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
->get();
return view('frontend.event.index', compact('events', 'tags', 'categories'));
}
You can use whereRelation for getting instead of using whereHas.
$customQuery->whereRelation('tags', 'tag_id', $id)
Using this structure you can shortan your code and optimize.
there is other relationship query method introduced in newer version check here
// Get event according to filters
$events = Event::where('status', '1')
->when($request->get('vehicle_type'), function ($query, $vehicleType) {
$query->where('vehical_type', '=', $vehicleType);
})
->when($request->get('tag'), function ($query, $tagId) {
$query->whereHas('tags', function ($query) use ($tagId) {
$query->where('tag_id', $tagId);
});
})
->when($request->get('category'), function ($query, $categoryId) {
$query->whereHas('categories', function ($query) use ($categoryId) {
$query->where('category_id', $categoryId);
});
})
->get();
You can use the when method for these types of conditions. You can view the documentation here.

How to filter by relation column Laravel

How to filter by relation column
tried this
->whereHas('customer',function ($query) use ($order){
$query->orderBy('first_name', $order);
})
and this
->with(['customer' => function ($query) use ($order) {
$query->orderBy('first_name', $order);
}])
Both did not work
with() are using eager loading, which turns this into two queries.
You need to use join() instead of with()
$orders = Order
::join('customers', 'order.customer_id', '=', 'customers.id')
->orderBy('customers.first_name')
->get();
OR
You may use sortBy() or sortByDesc() methods of Collection.
For example:
$orders = Order
::with('customer')
->get()
->sortBy('customer.first_name');
request {{host}}/admin/showcases?filterBy=companies:name it order by relation column companies
if simple {{host}}/admin/showcases?filterBy=name
it will be only orderBy("name")
->when(str_contains($filterBy, ':'),
function (Builder $query) use ($filterBy, $order, $columns) {
$table = explode(':', $filterBy)[0];
$key = Str::singular($table) . "_id";
$column = explode(':', $filterBy)[1];
$selfTable = $this->getTable();
$query->leftJoin($table, "$selfTable.$key", "$table.id")
->when($columns !== ['*'],
function ($query) use ($columns, $selfTable) {
$columns = array_map(function ($column) use ($selfTable) {
return "$selfTable.$column";
}, $columns);
$query->select($columns);
},
fn($query) => $query->select(["$selfTable.*"]))
->orderBy("$table.$column", $order);
},
function ($query) use ($filterBy, $order) {
$query->orderBy($filterBy, $order);
})

Laravel 8 relationship search returning empty result

I have this query:
$orders = Order::with(['company', 'products', 'user', 'status', 'seller'])->orderBy('id', 'DESC')->select('orders.*');
And it returns the relevant results as expected in a yajra datatable instance.
Now I would like to narrow down this result even more. I use it this way:
$orders = $orders->whereHas('user', function ($q) use ($request){
$q->searchFullName($request->seller);
});
I have created a scope in the model and it works for another function on my website. However it returns no results when calling it like that.
Even if I call the whereHas using a where statement, still the result is empty:
$orders = $orders->whereHas('user', function ($q) use ($request){
$q->where('first_name', 'like', '%'.$request->seller.'%');
});
The seller parameter is not empty. Even if I use a hardcoded string, the results are always empty.
The searchFullName method:
public function scopesearchFullName($query, $value){
return $query->where('first_name', 'LIKE', "%$value%")
->orWhere('middle_name', 'LIKE', "%$value%")
->orWhere('last_name', 'LIKE', "%$value%");
}
Full controller:
public function listOrdersData(Request $request)
{
if(!$request->ajax())
return Redirect::route('/');
$loggedUser = Auth::user();
if($loggedUser->hasRole('Super Administratör'))
$orders = Order::with(['company', 'products', 'user', 'status', 'seller'])->orderBy('orders.id', 'DESC')->select('orders.*');
else
$orders = Order::with(['company', 'products', 'user', 'status', 'seller'])->where('company_id', $loggedUser->company_id)->orderBy('id', 'DESC')->select('orders.*');
if (!empty($request->seller) && $request->seller != 'all') {
$orders = $orders->whereHas('user', function ($q) use ($request){
$q->searchFullName($request->seller);
});
}
return DataTables::of($orders)
->addColumn('products', function($orders) {
$products = "";
foreach($orders->products as $product)
$products = $products . $product->name . "<br>";
return $products;
})
->editColumn('company', function($orders){ return $orders->company->name; })
->editColumn('price', '{{$price}} kr')
->editColumn('user', function($orders){
return $orders->user->full_name;
})
->addColumn('seller', function($orders){
return $orders->seller->full_name;
})
->addColumn('status', function($orders){
return '<span class="chip lighten-4 purple purple-text">'. $orders->status->localized . '</span>';
})
->addColumn('contract', '<i class="material-icons">file_download</i>')
->addColumn('edit', '<i class="material-icons">edit</i>')
->rawColumns(['products', 'status', 'edit', 'contract'])
->make(true);
}
The issue is with scope method
public function scopesearchFullName($query, $value){
return $query->where('first_name', 'LIKE', "%".$value."%")
->orWhere('middle_name', 'LIKE', "%".$value."%")
->orWhere('last_name', 'LIKE', "%".$value."%");
}
Also make sure that only those user record returns who has orders.
Also for searching sellers order
$orders = $orders->whereHas('seller', function ($q) use ($request){
$q->searchFullName($request->seller);
});
so in Order model
public function seller()
{
return $this->belongsTo(User::class, 'seller_id', 'id');
}

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