Reputation: 429
Hi I'm having trouble getting data from database after adding a new function inside my controller. Can anyone explain to me this error and what should I do?
Background information: I have 3 different type of tables, personal_infos, user_infos and user_info1s table where personal_infos hasMany user_infos and user_info1s. I am using user_id as a foreign key to link together with personal_infos table
I'm using this video as a reference and want to do something like his end result (see 17.17 of video), but I get this error:
Error: Undefined variable: data
Route::get('/home/{id}', 'HomeController@getData')->name('home');
HomeController
public function getData($id) {
$data['data'] = DB::table('personal_infos')->get()->sortByDesc('upload_time');
if (count($data) > 0) {
return view('home',$data)
->with('test', personal_info::find($id)); // --> after adding this got error
} else {
return view('home');
}
}
Home.blade.php
<table class="table table-bordered">
<tr>
<th><strong><big>Name: </big></strong></th>
</tr>
<td>
<tr>
@foreach($data as $value)
<tr>
<th>{{HTML::link_to_route('home',$value->Name, array($value->id)) }}</th>
</tr>
@endforeach
</tr>
</tr>
</table>
Code that I have now after some changes:
HomeController:
public function getData($id = null){
$data['data'] = DB::table('personal_infos')->orderBy('created_at', 'desc')->get();
return view('home')
->with('personalInfos', $personalInfos)
->with('test', personal_info::find($id));
} }
home.blade.php
<ul>
@foreach ($personalInfos as $info)
<li>{{ HTML::link_to_route('home', $info->Name, [ $info->id ]) }}</li>
@endforeach
</ul>
Route
Route::get('/home/{id?}', 'HomeController@getData')->name('home');
personal_info model: (don't know if needed but just in case)
class personal_info extends Eloquent
{
protected $fillable = array('Email', 'Name', 'Mobile_No');
protected $table = 'personal_infos';
protected $primaryKey = 'id';
public function user_infos() {
return $this->hasMany('App\user_info','user_id');
}
public function user_info1s() {
return $this->hasMany('App\user_info1','user_id');
}
}
user_info1 and user_info (they are similar so I will just put 1 of them)
class user_info1 extends Eloquent
{
protected $fillable = array('hobby','sport','user_id');
public function personal_infos() {
return $this->belongsTo('App\personal_info', 'user_id', 'id');
}
}
Upvotes: 1
Views: 3928
Reputation: 16867
I can tell you're learning Laravel. There are several issues with the code posted in your question. Let's walk through each of these to see if we can improve your understanding.
First, let's take a look at the controller method signature:
public function getData($id)
This method expects an $id
parameter defined in the corresponding route. However, if we take a look at the route:
Route::get('/home/(:any)', 'HomeController@getData')->name('home');
...it doesn't properly declare that the URL contains a parameter (the video you're watching is about a very old version of Laravel). As described in the docs, we'll need to change the route signature to include a parameter for $id
:
Route::get('/home/{id}', 'HomeController@getData')->name('home');
Next, let's see how the controller method fetches its data:
$data['data'] = DB::table('personal_infos')->get()->sortByDesc('upload_time');
This query fetches all records from personal_infos
into a Collection
, and then sorts them by upload_time
. This is fine, but database engines can usually sort data faster than our PHP application, so we can instruct the DB to sort our data for us:
$data['data'] = DB::table('personal_infos')->orderBy('upload_time', 'desc')->get();
Notice how we changed the call to sortByDesc()
on the collection to orderBy()
for the database query. Now, the database sorts the results for us, so the collection doesn't need to.
Finally, let's try to fix the error you experience when passing the data to the view. Here's how your controller method currently does it:
if (count($data) > 0) { return view('home', $data) ->with('test', personal_info::find($id)); // --> after adding this got error } else { return view('home'); }
There are a couple problems with the code above:
count($data)
will always be greater than zero, because we're setting $data['data']
every time we call the method, so the else
block will never execute. This is probably fine because... count($data)
equals zero, the controller doesn't pass the view any data, so $data
in the view will be undefined
. The view in question uses @foreach
to loop through each of the results, so we can simplify the code in the controller method because foreach
won't iterate over an empty collection:
$personalInfos = DB::table('personal_infos')->orderBy('upload_time', 'desc')->get();
return view('home')
->with('personalInfos', $personalInfos)
->with('test', personal_info::find($id));
The view will receive two variables from the method above: $personalInfos
and $test
. I took the liberty of renaming $data['data']
into a more meaningful variable. This becomes very important as the project grows. Here's how we can use the data in the view:
<ul>
@foreach ($personalInfos as $info)
<li>{{ HTML::link_to_route('home', $info->Name, [ $info->id ]) }}</li>
@endforeach
</ul>
The template above outputs an unordered list as shown in the image in the question. The original table contains several row/column nesting errors and will not display the information like the question describes. As we can see, this template loops through each result in $personalInfos
. If $personalInfos
is empty, the list will not display any items.
If we want our controller method to handle the route with or without an ID, we'll need to tell Laravel that the ID is optional. For the route, a question mark (?
) after the parameter makes it optional:
Route::get('/home/{id?}', 'HomeController@getData')->name('home');
Then, we can set a default value for the controller method that handles the route. In this case, we'll use null
:
public function getData($id = null)
Of course, after we update this, we'll need to change the method to handle a null
$id
argument, which we use to fetch a personal_info
for the view's $test
variable. The question doesn't explain how the view uses $test
, so I'll leave this as an exercise to the reader :)
Upvotes: 1
Reputation: 8249
Follow are two ways to pass multiple variables to view
:
//Passing variable to view using with Method
return view('home')->with(['test'=>personal_info::find($id),'data'=>$data['data']]);
//Passing variable to view using Associative Array
return view('home', ['test'=>personal_info::find($id),'data'=>$data['data']]);
Upvotes: 0