Check If Model Exists - php

When searching for what should be a very basic and common test in Laravel, there seems to be much confusion on how to properly check weather or not a model exists and then do something with the model if it does. When searching through stackoverflow, laracasts, and the laravel documentation itself, it does not become anymore clear. If I for example run this query,
$restaurant = Restaurant::find($input["restaurant_id"]);
There are various stack overflow posts that would have me check the count(), use the exists() method which does not seem consistent, or use firstOrFail() which throws an exception. All I want to do is run a call like the one above, check if $restaurant is a valid model, and then do something if it is. There is no need for an exception in my case and I don't want to have to have to run the query again after using something like count() or exists(). The documentation has no useful information on this either which allows 4 different variable types to be returned without any mention of which case will trigger which return. Does anyone have a good handle on this topic?
Laravel checking if record exists
Eloquent ->first() if ->exists()
https://laravel.com/api/5.2/Illuminate/Database/Eloquent/Builder.html#method_find

You don't need to run any additional queries. If the record does not exist, find() will return null. You can just use a simple if to check:
if($restaurant = Restaurant::find($input["restaurant_id"]) {
// Do stuff to $restaurant here
}

You can also use
$restaurant = Restaurant::findOrFail($input["restaurant_id"]);
Sometimes you may wish to throw an exception if a model is not found. This is particularly useful in routes or controllers. The findOrFail and firstOrFail methods will retrieve the first result of the query. However, if no result is found, a Illuminate\Database\Eloquent\ModelNotFoundException will be thrown:
From: https://laravel.com/docs/5.1/eloquent

Its very clear in laravel docs about your question, find(),first(),get(), all return null if the model not exist,
$model = Restaurant::find(111); // or
$model = Restaurant::where('id',111)->first();
if(!$model){ //if model not exist, it means the model variable is null
}

Related

Catch and save elements in Laravel, not by primaryKey

I need to get an element from the database, but I can not get it by the FIND method, since FIND only finds it by the primaryKey and what I need is not by my primaryKey. So I did like this:
$user = Pac::find($request->pac_id);
$element = query()->where('med_cart', $user->pac_id)->get();
$element->med_obs = $request->med_obs;
$element->save(); // error
Now I need to save this element, however, I can not use the SAVE method, as I believe it is fully connected with FIND and FINDORFAIL (if anyone knows, explain to me which methods I can use the SAVE method).
How can I save them the way I did? Or is there some other way to do it?
Because I need to get the element with a data other than the primaryKey and then save it, then I can not use FIND or FINDORFAIL, I think.
The function ->find() returns an Eloquent Model instance and you can then call ->save() on the model instance.
You're using ->get() which returns a Collection.
To update your query (that may target one or more entries) just perform the update statement directly from the QueryBuilder by replacing ->get() with ->update(['med_obs' => $request->med_obs]).
Be aware that when doing this you are now using Fluent queries, instead of eloquent. This means that any logic you may have defined in the boot function of your model is not evaluated.
If you are certain that you only have a single result you can append ->first() to your query, which will return a Model of the first result that matches your ->where clause. You can then call ->save() on it:
$user = Pac::find($request->pac_id);
$element = query()->where('med_cart', $user->pac_id)->first();
$element->med_obs = $request->med_obs;
$element->save();

Eloquent findOrFail()->get()

Bit of a rookie error I know, but can I ask...
Why does
findOrFail()->get();
or
findOrFail()->first();
Return the whole collection, opposed to just failing? The correct syntax I know is just:
findOrFail();
However an accidental ->get() on the end has caused me a nightmare!
The findOrFail($id) method returns a single model by finding through id column and throws an exception - ModelNotFoundException, if model is not found. The get() method return the collection of models/rows.
If you need to find and expect only one model in return by using id, use findOrFail() method only. You dont have to use get() in the end. You can catch the exception and show the respective message in response. Also, you don't have to use first() method in this case, because findOrFail() method will return only one model result.
If you expect a collection of models, use get() method in the end. If there is no result, you'll get an empty collection or array and no exception will be thrown in this case, as the result will be an empty collection/array.
Both findOrFail and firstOrFail throws an exception if the model is not found. This is the default behaviour : https://laravel.com/docs/5.6/eloquent#retrieving-single-models

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

what is difference between where and find in laravel

when I write this $thread = Thread::find($id); then I write {{$thread->title}} it gives me the title of the thread, but when I write $thread = Thread::where('id','=',$id); then I write {{$thread->title}} it gives me an error.why is that happening?
You should write:
$thread = Thread::where('id','=',$id)->first();
to get one column, else laravel will understand it as array.
You need to call the get() (or any of its variants) method to execute the actual query when using where.
Thread::where('id','=',$id)->get();
Otherwise Thread::where('id','=',$id) just gets you an instance of eloquent's query builder.
find() on the other hand will automatically run a query for whatever it is you want to find by you can't do all sorts of useful stuff (e.g. orderBy, paginate, etc.) that you can very easily pull of using the query builder.

Does the Yii CActiveRecord class have a first() method?

I need to just get the first record from a Yii CActiveRecord derived class. In Rails I would just be able to do this:
post = Post.first
I thought I could do the same thing with Yii like this:
$post = Post::model()->first();
But that method doesn't exist. Do I have to just do find with a condition to get the first record?
I don't see first() in the docs for CActiveRecord so I assume the answer is no, it doesn't have a first method. So how would one go about querying just the first record?
This works but sure is an ugly hack. Surely there's a better way.
$first = Post::model()->findAll(array('order'=>id, 'limit'=>1));
Yii isn't going to make any assumptions about how your data should be ordered. Good database design requires that if you use a surrogate key, that key should have a meaningless value. That means NOT using it for ordering.
That issue aside, here is probably the best way to do your query:
$first = Post::model()->find(array('order'=>'id ASC'));
By using find instead of findAll you automatically apply a LIMIT 1 to your result. I would not skip the inclusion of the order by clause, as that insures that the database will order the results consistently.
If you use this query a lot, you can create the following method. UPDATE: Modified it to throw an exception when the primaryKey is composite or missing. We could add more error checking as well, but we leave that as an exercise for the reader. ;)
public function first($orderBy = null){
if(!$orderBy){
$orderBy = self::model()->tableSchema->primaryKey;
}
if(!is_string($orderBy)){
throw new CException('Order by statement must be a string.');
}
return self::model()->find(array('order'=>$orderBy));
}
Then include this method in a class which extends CActiveRecord, and then extend all your models form that class.
The wrapper I wrote will by default order results by the primary key, but you could optionally pass a different column and direction (ASC OR DESC) if you wish.
Then if you do this for the post class, you can access the first model like so:
$first = Post::model()->first();
CActiveRecord::find() returns only one model.
$first=Post::model()->find();
Yii2 asks for a condition when doing a findOne().
You could do a find() following with no conditions and just return one()
$first= Post::find()->one();
To really be sure you could just add a orderBy clause to it:
$first= Post::find()->orderBy(['id' => SORT_ASC])->one();
Same goes for the command function:
$first= \Yii::$app->myDatabase->createCommand('SELECT * FROM Post ORDER BY id ASC')->queryOne();

Categories