Property [bId] does not exist on this collection instance - php

I have a pages controller.I wanna get some information stored in my db when /myshopping requested.
This is my controller code :
public function myshopping()
{
$Buylist=DB::table('orders')->where('id','=',Auth::user()->id)->orderBy('oId','desc')->get();
$Bookinfo=DB::table('books')->where('bId','=',$Buylist->bId)->first();
return view('shop.myshopping',compact('Buylist','Bookinfo'));
}
Thank you very much.

Using->get() on a QueryBuilder returns a Collection (fancy wrapper for PHP arrays), so $Buylist is a group of records from your orders table, as opposed to a single record.
If you change your logic to use ->first():
$Buylist=DB::table('orders')->where('id','=',Auth::user()->id)->orderBy('oId','desc')->first();
Then you can access $BuyList->bId without issue (unless $BuyList returns null, but that's a different issue).

Related

Does a one-to-one relationship in Laravel always need first()?

I have a one-to-one relationship between User and UserSettings models,
But (after $user = auth()->user()) when I try $user->settings()->something it throws an Undefined property error.
It's gone when I use $user->settings()->first()->something...
My question is, is this how it's supposed to work? or am I doing something wrong?
You cannot directly run $user->settings()->something.
Because when you call $user->settings(), it just return Illuminate\Database\Eloquent\Relations\HasOne object.
So it is not the model's object, you need to take the model's object and call its attribute like this.
$user->settings()->first()->something;
Dynamic Properties
Since you have one-to-one relationship between User and UserSettings.
If you have a one-to-one relationship in your User model:
public function settings()
{
return $this->hasOne('App\Models\UserSettings', 'user_id', 'id');
}
According to Laravel doc
Once the relationship is defined, we may retrieve the related record using Eloquent's dynamic properties. Dynamic properties allow you to access relationship methods as if they were properties defined on the model:
Eloquent will automatically load the relationship for you, and is even smart enough to know whether to call the get (for one-to-many relationships) or first (for one-to-one relationships) method. It will then be accessible via a dynamic property by the same name as the relation.
So you can use eloquent's dynamic properties like this:
$user->settings->something; // settings is the dynamic property of $user.
This code will give you a result of collection.
$user->settings;
So calling 'something' is not available or it will return you of null, unless you get the specific index of it.
$user->settings()->something
while this one works because you used first() to get the first data of collection and accessed the properties of it .
$user->settings()->first()->something
The first method returns the first element in the collection that passes a given truth test
see docs here laravel docs
If you want to get the user settings itself simply do this:
$user->settings
Then you can get the fields of the settings doing this:
$user->settings->something
When you do this $user->settings() you can chain query after that. E.g.
$user->settings()->where('something', 'hello')->first()
That's why the output of $user->settings and $user->settings()->first() are the same.
Auth only gives you user info;
Try the following code:
$user = User::find(auth()->user()->id);//and then
$user->settings->something;

When not or should use get() in Laravel 5

I need to understand when/not to use get(); in Laravel 5.
PHP warning: Missing argument 1 for Illuminate\Support\Collection::get()
Google shows me answers to their issue but no one really explains when you should/not use it.
Example:
App\User::first()->timesheets->where('is_completed', true)->get(); // error
App\Timesheet::where('is_completed', true)->get(); // no error
Fix:
App\User::first()->timesheets()->where('is_completed', true)->get(); // no error
Noticed the timesheets() and not timesheets? Could I have a detail explanation for what is going on, please?
I'm coming from a Ruby background and my code is failing as I do not know when to use () or not.
I'll try to describe this as best I can, this () notation after a property returns an instance of a builder, let's take an example on relationships,
Say you have a User model that has a one-to-many relationship with Posts,
If you did it like this:
$user = App\User::first();
$user->posts();
This here will return a relationship instance because you appended the (), now when should you append the ()? you should do it whenever you want to chain other methods on it, for example:
$user->posts()->where('some query here')->first();
Now I will have a the one item I wanted.
And if I needed say all posts I can do this:
$user->posts;
or this
$user->posts()->latest()->get();
$user->posts()->all()->get();
So the key thing here is, whenever you want to chain methods onto an eloquent query use the (), if you just want to retrieve records or access properties directly on those records then do it like this:
$user->posts->title;
Well, ->timesheet returns a collection, where ->timesheet() returns a builder.
On a Collection you can use ->where(), and ->get('fieldname'), but no ->get().
The ->get() method can be used on a builder though, but this will return a collection based on the builder.
Hope this helps.
The 'problem' you are facing is due to the feature of being able to query relations
When accessing a relation like a property, ->timesheets, the query defined in the relationship is executed and the result (in the form of a Collection) is returned to you.
When accessing it like a method, ->timesheets(), the query builder is returned instead of the resulting collection, allowing you to modify the query if you desire. Since it is then a Builder object, you need to call get() to get the actual result, which is not needed in the first case.
When you use ->timesheets you are accessing a variable, which returns the value of it (in this case an instance of Collection).
When you use ->timesheets() you are invoking whatever is assigned to the variable, which in this case returns an instance of Builder.
whilst pascalvgemert's answer does answer your problem regarding Laravel, it does not explain the difference between accessing or invoking a variable.
In simple term
$user = App\User::get();
is used to fetch multiple data from database
rather
$user = App\User::first();
is used to fetch single record from database

Laravel nested relationship not working

I have a user model which stores basic user information such as username, password etc.
There are also 3 types of user, Student, Staff and Parent. Each type also has a seperate model. For example, there is a Student model which belongs to a User model.
I also have a relationships table, which stores relationships between students and parents. This relationship is stored in the User model.
If I do something like:
App\Student::first()->user->relations;
It happily returns a collection of related parents.
In my Students model, I have a method called hasParent() which accepts a given user ID, and checks to ensure the student has a parent with that id. In that method, I have the following:
public function hasParent($parent)
{
return $this->user->relations->where('id', $parent)->count() === 1;
}
However, this returns an error Cannot call 'where' on a non-object. If I debug further, $this->user->relations returns an empty array.
The problem is, like above, if I call the methods separately, I get the results I want.
So to clarify, if I run:
App\Student::first()->user->relations;
This returns a collection of users just fine.
In my Student model however, if I call:
$this->user
Then I get the correct student
If I call
$this->user->relations
I get an empty array. Which doesn't make sense! Can anyone shed any light on this, or what I might be doing wrong? If you need any further info, please let me know.
You need to call where on the relation like below.
public function hasParent($parent)
{
return $this->user->relations()->where('id', $parent)->count() === 1;
}
See the parenthesis after the relations. If you call the relation without the parenthesis Laravel returns you a collection. To get the builder you need to call the relation with the parenthesis.
I'd suggest - to avoid creating a huge query overhead (which you'll do by calling where and count on the Query builder, not the collection) - to do what you're doing already, except using Illuminate Collections filter-method:
public function hasParent($parent)
{
return $this->user->relations->filter(function($relation) use ($parent){return $entity->id === $parent;})->count() === 1;
}

How to share a variable between master layout and a view

I have the following static method in my Guest model to retrieve all guests at location 1:
public static function getGuests()
{
return self::where('location_id', '=', 1)->get();
}
I also got the following static method to retrieve and display the number of guests at location 1.
public static function getCount()
{
return self::getGuests()->count();
}
I later call the getGuests() in my GuestController and pass all the guests to the view guests/index.blade.php to display data in a table.
I also call getCount() from my BaseController (see below) to make the count variable available both in the menubar in the layout/layout.blade.php file and the header of guests/index.blade.php.
View::share('numGuests', Guest::getCount());
By doing this i naturally end up with an expensive duplicated query to the DB since GetCount() calls getGuests(). Is there a better way to display the number of counts, both in the master layout file and the embedded view, without having to do the duplicate query call?
View::share shouldn't be calling the `Guest::getCount()' twice. It should just call it once and then pass it in. If not though can't you just cache the value in a variable and then pass it in? Then its definitely not getting queried twice.
$guestCount = Guest::getCount();
View::share('numGuests', $guestCount);
I might be misunderstanding here - are you also calling Guest::getCount() later on from your GuestController? Sorry - can't comment on main questions yet to ask.
I found a quick and low-cost solution by simply just calling the count() directly on the query, instead on the function call.
public static function getAll($locationId)
{
return self::whereLocationId($locationId)->with('country')->get();
}
public static function countAll($locationId)
{
return self::whereLocationId($locationId)->count();
}
This left me me with two separate queries, where the count is onsiderably lower cost:
select * from `guests` where `location_id` = '2'
and
select count(*) as aggregate from `guests` where `location_id` = '2'
It can probably be made even quicker by selecting only the neccesary columns instead of *. In cases where the query is more complicated and require more WHERE clauses, it can easily be kept DRY by using query scopes. Thanks for massaging my brain.

Doctrine Collection contains empty model object

I am using Doctrine 1.2 with Zend Framework. When I fetch a result set as a Doctrine collection, the collection object contains an empty model object of a given type if the returned result-set returned from the DB is empty.
This is quite confusing as we are relying on the count method of Doctrine_Collection to show either a listing of the returned results or an appropriate message when the query returns an empty collection.
Any help will be highly appreciated.
I also thought this was annoying. You want to test for actual results by calling Doctrine_Collection::count(), such as this scenario that we had:
if ( $collection->count() ) {
// display some widget of the members of Doctrine_Collection
}
The method suggested by yitznewton works for me.
Alternatively, you can test a known field for the first element (0) in the collection.
if ($collection[0]->id) {}

Categories