I have a Model called OfficeHours which as various attributes and the model User belongsTo OfficeHours. I am trying to fetch a particular element from a collection but am getting blank in blade.
public function office_hours() {
return $this->hasMany(OfficeHours::class);
}
public function user(){
return $this->belongsTo(User::class);
}
In Blade when i do the following:
{{$logged_in_user->office_hours->where('dow',2)}}
it works and gets me the following collection:
{"2":{"id":3,"user_id":4,"dow":2,"fromtime":"07:00:00","totime":"16:00:00","created_at":"2019-01-31 14:48:32","updated_at":null}}
now how i do i get the elements of that collection?
i tried
{{$logged_in_user->office_hours->where('dow',2)->get('fromtime')}}
but it gives me blank
How do i access the elements?
To preface, you shouldn't be doing that kind of logic in the view file, this is what controllers are for. You'd be able to do $fromtime = ...; and pass that to the view via return view(...)->with(["fromtime" => $fromtime]);
But, that being said, you should be able to do
{{ $logged_in_user->office_hours->where("dow", 2)->first()->fromtime }}
Note you're gonna get an error if ->where("dow", 2) doesn't return a Collection, as null doesn't have a ->first() method on it.
Related
I was reading a blog related Repository Pattern. I saw use of withBlogs method.
public function index()
{
$blogs = $this->blogRepository->all();
return view('blog')->withBlogs($blogs);
}
I never see something like this before. What is the purpose of it or what it's doing?
it is laravel's magic methods
you can name the method anything you want with with() in laravel
let me explain you by example, the following code you write in your controller method
return view('index')->withName('Name')->withFullName('Full Name')->withaddress('Your address')->withcountryName('CountryName');
then you can access the values in view explained below
withName('Name') in view it becomes $name
withFullName('Full Name') in view it becomes $fullName
withaddress('Your address') in view it becomes $address
withcountryName('CountryName') in view it becomes $countryName
It is used for passing data into views. The with method returns an instance of the view object so that you can continue chaining methods before returning the view. All of the syntax below archives the same thing:
return view('blog')->withBlogs($blogs);
return view('blog')->with('blogs', $blogs);
return view('blog')->with(compact('blogs'));
return view('blog', compact('blogs'));
I need to know how to assert that Laravel Controller returns view with proper data.
My simple controller function:
public function index() {
$users = User::all();
return view('user.index', ['users' => $users]);
}
I am using functions such as assertViewIs to get know if proper view file is loaded:
$response->assertViewIs('user.index');
Also using asserViewHas to know that "users" variable is taken:
$response->assertViewHas('users');
But I do not know how to assert if retrieve collection of users contain given users or not.
Thanks in advance.
In tests I would use the RefreshDatabase trait to get a clean database on each test. This allows you to create the data you need for that test and make assumptions on this data.
The test could then look something like this:
// Do not forget to use the RefreshDatabase trait in your test class.
use RefreshDatabase;
// ...
/** #test */
public function index_view_displays_users()
{
// Given: a list of users
factory(User::class, 5)->create();
// When: I visit the index page
$response = $this->get(route('index'));
// Then: I expect the view to have the correct users variable
$response->assertViewHas('users', User::all());
}
The key is to use the trait. When you now create the 5 dummy users with the factory, these will be the only ones in your database for that test, therefore the Users::all() call in your controller will return only those users.
How do I call with directly on an object thats been automagically fetched through a route with the same results as if it were fetched through where?
Let me explain through code!
My route (same in both):
Route::get('post/{post}', 'PostsController#show');
Alternative 1:
My Controller:
public function show(Post $post){
$postWithComments = Post::where('id', $post->id)->with('comments')->first();
}
Output: The comments of the intended post.
Alternative 2:
My Controller:
public function show(Post $post){
$postWithComments = $post->with('comments')->first();
}
Output: The comments from the first of ALL posts.
Desired output: Same as alternative one.
How can I modify the query in alternative 2 to output the same as alternative 1?
I am thinking that it is unnecessary to make first the where-request as I already have the object loaded. So I am thinking that I would want to do this to reduce DB calls. Or am I thinking wrong?
There are two ways to solve this:
Query related data with lazy loading:
$post->comments; // this did the trick - comments for post will queried here
return $post; // here posts already has comments collection
Setup model binding and use eager loading:
At your Post model add resolveRouteBinding method:
class Post extends Model
{
public function resolveRouteBinding($id)
{
return $this->where('id', $id)->with(['comments'])->first();
}
}
Then your controller will recieve Post instance with already loaded comments
I am in the process of trying to clear up a variety of little aspects of a project I inherited and am in the process of removing the odd Route Key Names from the models. I am testing with the easiest model which had the following in it:
public function getRouteKeyName(){
return 'url_string';
}
I just deleted the lines and saved it but unfortunately it returned "Sorry this page could not be found" when using the regular ID, but brought up successfully using the field contents of url_string.
The route in web.php uses the following: /carrier/customer/show/{customer}
What else do I have to do to remove its dependence on the url_string field?
Update with controller method
public function show(Customer $customer)
{
return view('customers.show', compact('customer'));
}
I'm stuck on an issue where I'm trying to clean up code presented to me, and I feel like I must've just been at this too long and can't see this issue.
At the moment I have the following code in one of my models:
public function attachments(){
return $this->hasMany(volunteerAttachment::class, 'volunteerID','id');
}
public function photoID() {
$photoID= $this->attachments()->where('category','Drivers License')->orderBy('endDate','desc')->limit(1);
return $photoID;
}
What I would like to do is what I believed was relatively simple in replacing the limit(1) of the function photoIdentification with a simple first().
But when I try that and simply put {{$volunteer->photoID->id}} in my blade, it simply returns the error App\volunteer::photoID must return a relationship instance.
I do however know that there is a relationship because if I continue to use the limit(1) and put:
#foreach($volunteer->photoID as $id)
{{$id->id}}
#endforeach
It returns the relation and document correctly.
$volunteer is the variable for that particular model App\volunteer, and the following is how it is defined in the controller:
public function show(Volunteer $volunteer){
return view('volunteer.show', compact('volunteer'));
}
The function photoID() will still return a full volunteerAttachment object. If you want to get the id using the first() function you will have to select the id property on the object like so:
{{ $volunteer->photoID()->id }}
You could also create an accessor on the model that directly returns this property:
public function getPhotoidAttribute($value)
{
return $this->attachments()->where('category','Drivers License')->orderBy('endDate','desc')->first()->id;
}
Now in blade you can just use:
{{ $volunteer->photoid }}
When you call a function of a model as a variable Laravel assumes you try to return a related model. Try with an accessor instead:
public function getPhotoidAttribute($value) {
$photoID= $this->attachments()->where('category','Drivers License')->orderBy('endDate','desc')->first();
return $photoID->id;
}
and call it like this:
{{ $volunteer->photoid }}