Laravel 5.2 Eloquent Use of Select in Eagerly Loaded Query - laravel

I can get this to work using a select:
User::whereNotIn('id', $ids)
->select(['id', 'email'])
->with('profile')
->get();
I'd like to only retrieve a couple keys in a user profile that is eagerly loaded. I'd like to do something like this:
User::whereNotIn('id', $ids)
->select(['id', 'email'])
->with(['profile', function ($query) {
$query->select(['id', 'user_id', 'first_name', 'last_name']);
}])->get();
Or:
User::whereNotIn('id', $ids)
->select(['id', 'email'])
->with(['profile', function ($query) {
$query->addSelect(['id', 'user_id', 'first_name', 'last_name']);
}])->get();
But this doesn't seem to work, and I get this error:
ErrorException in Builder.php line 1034:
explode() expects parameter 2 to be string, object given
Thrown in /Illuminate/Database/Eloquent/Builder.php:
/**
* Parse the nested relationships in a relation.
*
* #param string $name
* #param array $results
* #return array
*/
protected function parseNestedWith($name, $results)
{
$progress = [];
// If the relation has already been set on the result array, we will not set it
// again, since that would override any constraints that were already placed
// on the relationships. We will only set the ones that are not specified.
foreach (explode('.', $name) as $segment) { // <--- line 1034
$progress[] = $segment;
if (! isset($results[$last = implode('.', $progress)])) {
$results[$last] = function () {
//
};
}
}
return $results;
}
Is there a way to accomplish this?

Use "addSelect" instead of "select" inside the eager load constraint closure
User::whereNotIn('id', $ids)->select(['id', 'email'])
->with(['profile' => function($query) {
$query->addSelect(['id', 'user_id', 'first_name', 'last_name']);
}])->get();
You have to include the foreign key on the addSelect otherwise nothing will be loaded

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

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 relathionship with query builder get error

I have 3 tables this table is related to, I will call this table with
belanja (parent)
anak_belanja (child)
supplier (has relation with parent)
I can create this relation from parent and child but on table supplier I get an error. Usually I use "with" and I get no error, but now I use query builder and I have a problem
My Belanja Model
public function supplier()
{
return $this->belongsTo(\App\Models\Suplier::class ,'supplier_id');
}
My Anak_Belanja model
public function belanja()
{
return $this->belongsTo(\App\Models\Belanja::class ,'belanja_id');
}
and this is my controller
public function render()
{
$user_id = Auth::user()->id;
$sub = SubRincianUraianKegiatan::where('user_id', $user_id)
->where('id' , $this->newid)
->pluck('uraian', 'id');
$sup = Supplier::all()->pluck('nama' ,'id');
$data = DB::table('belanja AS t')
->select([
't.id',
't.uraian',
't.tgl_belanja',
't.supplier_id',
DB::raw('coalesce(sum(p.harga * p.qty),0) AS total_order')
])
->leftjoin('suplier AS s','t.suplier_id','=','s.id') // on here i think this error
->leftjoin('anak_belanja AS p','p.belanja_id','=','t.id')
->where('sub_id', $this->newid)
->where('uraian', 'like', '%'.$this->search.'%')
->groupBy('t.id')
->groupBy('t.uraian')
->groupBy('t.tgl_belanja')
->groupBy('t.suplier_id')
->paginate(10);
return view('livewire.detail-belanja-lw',
['data' => $data ,
'sup' => $sup,
'sub' => $sub,
]);
}
In my blade I try to add supplier like that
{{$i->supplier->nama}}
but I get an error
Undefined property: stdClass::$supplier
Can someone explain my mistake?
$data = DB::table('belanja AS t')
->select([
't.id',
't.uraian',
't.tgl_belanja',
't.suplier_id',
DB::raw('coalesce(sum(p.harga * p.qty),0) AS total_order'),
DB::raw('s.nama as nama')
])
->leftjoin('suplier AS s','t.suplier_id','=','s.id') // on here i think this error
->leftjoin('anak_belanja AS p','p.belanja_id','=','t.id')
->where('sub_id', $this->newid)
->where('uraian', 'like', '%'.$this->search.'%')
->groupBy('t.id')
->groupBy('t.uraian')
->groupBy('t.tgl_belanja')
->groupBy('t.suplier_id')
->paginate(10);
try this.

Laravel: Selective drop down lists

So my drop down list works that I HAVE to select both options for it to display a list of hotels based on the criteria selected (Distance and price), but I want to make sure that the user can find all hotels based on just Price, for example. When I do this, no hotels appear and my drop down list doesn't quite work. So how would I exactly implement code that will let the user select all the hotels based on just the ONE criteria.
SearchController.php
public function index(Request $request)
{
$distances = DB::table('posts')->select('distance')->distinct()->get()->pluck('distance');
$prices = DB::table('posts')->select('price')->distinct()->get()->pluck('price');
$post = Post::query();
if ($request->has('price')) {
$post->where('price', $request->price);
}
if ($request->has('distance')) {
$post->where('distance', $request->distance);
}
return view('Pages.search', [
'distances' => $distances,
'prices' => $prices,
'posts' => $post->get(),
]);
}
Have you tried using when?
public function index(Request $request)
{
// Unnecessary select * changed to select only the columns you need.
$distances = DB::table('posts')->select('distance')->distinct()->get(['distance'])->pluck('distance');
$prices = DB::table('posts')->select('price')->distinct()->get(['price'])->pluck('price');
$post = Post::when($request->has('price'), function ($query) use ($request) {
$query->where('price', $request->price);
})
->when($request->has('distance'), function ($query) use ($request) {{
$query->where('distance', $request->distance);
})
->get();
/* php >= 7.4
$post = Post::when($request->has('price'), fn($query) => $query->where('price', $request->price))
->when($request->has('distance'), fn($query) => $query->where('distance', $request->distance))
->get();
*/
return view('Pages.search', compact('distances', 'prices', 'post');
}
So instead of the use of 'has' i simply implemented the 'filled' and this ensured that my filtering worked.

Status is not changing API in laravel

I try to build an API for an android app it shows complaint details when an employee enter remarks of the complaint then change the status into on working from a drop-down menu in the app. But it throws an error like this.i use postman to run the API
The status is not changing and remarks entry is not working
"SQLSTATE[42S22]: Column not found: 1054 Unknown column '0' in 'field list' (SQL: update complaints inner join monitorings on monitorings.complaint_id = complaints.temp_complaint_id set 0 = complaints.root_cause, 1 = monitorings.status, updated_at = 2018-07-17 12:35:27)"
public function complaint_onworking(Request $request)
{
$validator = Validator::make($request->all(), [
'rootcause' => 'required',
]);
if ($validator->fails()) {
return $this->sendError('Validation Error.', $validator->errors());
}
//
$compid = $request->input('comp_id');
$user_id = $request->input('user_id');
$rootcause = $request->input('rootcasue');
$onworkrequest = Complaint::join('monitorings',
'monitorings.complaint_id', '=', 'complaints.temp_complaint_id')
->select([
'monitorings.complaint_id', 'monitorings.current_user_id','complaints.root_cause'
])
->where([
['complaints.temp_complaint_id', '=', $compid],
['monitorings.current_user_id', '=', $user_id]
])
->get();
// return $onworkrequest;
foreach ($onworkrequest as $onworking) {
if ($onworking) {
$onwork =Complaint::join('monitorings','monitorings.complaint_id', '=', 'complaints.temp_complaint_id')
->where([['complaints.temp_complaint_id', '=', $compid], ['monitorings.current_user_id', '=', $user_id]])
->update([['monitorings.root_cause', '=', $rootcause],['monitorings.status', '=', 1]]);
// $cmpt=array('routcause' =>$rootcause);
$success['routcause']=$onwork->root_cause;
return $this->sendResponse($success, 'Complaint is in onworking');
} else {
$success = "";
return $this->sendResponse($success, 'No change in status');
}
}
}
A couple of things I spotted in your Eloquent query.
Model::update should be passed an array of fields to be updated as keys and values to update with.
/**
* Update the model in the database.
*
* #param array $attributes
* #param array $options
* #return bool
*/
public function update(array $attributes = [], array $options = [])
See Model::update method signature / Examples
$onwork = Complaint:::join(
'monitoring',
'monitoring.complaint_id', '=', 'complaints.temp_complaint_id')
->where([
'complaints.temp_complaint_id' => $compid,
'monitoring.primary_user_id' => $user_id
])
->update([
'monitoring.routcause' => $rootcause,
'monitoring.status' => 1
]);
Also, See Model::select method signature
$onworkrequest = Complaint:join(
'monitoring',
'monitoring.complaint_id', '=', 'complaints.temp_complaint_id')
->select([
/* THIS ISN'T RIGHT
['monitoring.complaint_id', '=', $request->input('comp_id')],
['monitoring.primary_user_id', '=', $request->input('user_id')],
['routcause', '=', $request->input('rootcause')] */
])
->where([
['complaints.temp_complaint_id', '=', $compid],
['monitoring.primary_user_id', '=', $user_id]
])
->get();
For the select query, you either pass an array of columns to select or arguments of columns to select. e.g.
...
->select('monitoring.complaint_id', 'monitoring.primary_user_id', 'routcause')
There are more examples of the Illuminate\Database\Query\Builder API in the tests here.
I have fixed the error and works fine.there was a problem in the update query and I fixed, thanks for the help guys really appreciate it
$onwork=Complaint::where([['temp_complaint_id','=',$compid],['status','!=','5']])
->update(['root_cause'=>$rootcause,
'status'=>'7']);

Resources