1

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

What I want to do: enter image description here Route.php

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');
    }
}
9
  • is it in controller ? Commented Oct 16, 2017 at 3:45
  • The error is coming from home.blade.php but I think the cause is from the controller, I see some people used compact for this kind of situation but for me it doesn't seem like it worked Commented Oct 16, 2017 at 3:47
  • Although unrelated to the error, the nesting of some of the table rows and cells is off. <td> (cells) should be nested inside <tr> (rows), and <th> (table header cells) should be nested in a <tr> inside a <thead> element. Commented Oct 16, 2017 at 4:40
  • Another issue: $id looks undefined in personal_info::find($id). Are you passing in the $id? Commented Oct 16, 2017 at 4:47
  • @CyRossignol I tried doing public function getData($id) but still not working Commented Oct 16, 2017 at 4:49

2 Answers 2

1

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:

  1. 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...
  2. ...when 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 :)

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for the clear explanation and also telling me what are the right and wrong to do. But after changing the following things I received the error "Undefined variable: personalInfos " at home.blade.php. I'm guessing it is similar to the original error "undefined variable: data" as shown in my question. I went and look around some more information and saw some people using compact to pass the data to blade.php. Is it possible to use it? If yes, how would you do it since the example I saw were something like array so I am kind of confused on how to write the code for it
@blastme Yes, we can use compact(). This PHP function creates an array from variables in the current scope. We pass the variable names we want as strings: compact('personalInfos'). Personally, I don't like it much, but some people do. However, if you're still getting that error, compact() won't help. It seems like a different controller method is returning the view (without data). You can test by adding a dd('test') to the beginning of the controller method.
In the same controller a default function has already been created but I didn't dare to touch it would this be the cause? public function index() { return view('home'); } and in route "Route::get('/home', 'HomeController@index')->name('home');" So do I take this 2 out? Because when I remove it, it will just tell me page not found. So sorry for the messy text here, I don't know how to format it properly
@blastme Good catch. When the URL doesn't contain an ID, that route gets called instead of getData(). I updated my answer to show how we can use an optional parameter. This lets us use getData() for both cases, and we can delete the other route and controller method.
instead of putting it as null, can I make the id to be compulsory instead? Because now I am still getting the same error as before and I saw that my id is null when it shouldn't be, the array the put there was 1. So is there anything that I should take note of? So sorry for asking simple questions, still under my learning phase for laravel
|
0

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']]);

5 Comments

Are you sure $data is populated or it would/can be empty? In that case, add a check in blade @if(isset($data)). Which means, its going in else and not in if condition.
Before I add this part "->with('test', personal_info::find($id));" I was able to get the data but because I want to get it through id I added that code but after that an error appeared so could it be because of my route or controller problem when I try to find id?
I still get the same error when I try to put in @if(isset($data))
I updated the answer with two ways in which multiple parameters can be sent to View
Nope still same error, is there a need to put $id inside the public function getData()? (eg: public function getData($id))

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.