Search code examples
phpoopmodel-view-controllerpdo

Getting Undefined variable while trying to retrieve user data from database


I was trying to retrieve data from the "user_app" table into my table form in the view page.

Here's my Controller(method):

public function getUserApps($email) {

        $userAppsModel = new UserApps($this->pdo);

        $apps = $userAppsModel->get($email);

        return $this->view('user/dashboard', ['apps' => $apps]);
    }

Here's the method I used to get the data:

public function get($email) {
        
        $sql = "SELECT * FROM $this->table WHERE email = :email";
        $stmt = $this->pdo->prepare($sql);
        $stmt->bindParam(':email', $email, PDO::PARAM_STR);
        $stmt->execute();
        $user = $stmt->fetch(PDO::FETCH_ASSOC);
    
        return $user;
    }

and here's my View Page (dashboard.php) Line 107:

<h1>User List</h1>
        <table>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Email</th>
                <th>Role</th>
            </tr>
            
       

     **Line 107:**    <?php foreach ((array) $apps as $app) : ?>
            <tr>
                <td><?= $app['app_name'] ?></td>
                <td><?= $app['app_desc'] ?></td>
                <td><?= $app['app_cat'] ?></td>
            </tr>
            <?php endforeach; ?>

        </table>

My view() method:

protected function view($filename, $data = []) { 
    if (file_exists('../view/' . $filename . '.php')) { 
        require_once '../view/' . $filename . '.php';  
    }
}

Error Getting: Warning : Undefined variable $apps in C:\xampp\htdocs\xxxxxx\view\user\dashboard.php on line 107


Solution

  • Your view() method is not extract()ing the $data argument, so $data['apps'] is not being made available to your view.

    Prior to requireing your view file, you need to use extract($data).

    NOTE: extract() is a dangerous method and should NEVER be used with untrusted data (such as from $_GET or $_POST), because extract makes array keys available as variables.

    Solution:
    Here is a rewritten version of your view() method using extract:

    protected function view($filename, $data = []) { 
        if (file_exists('../view/' . $filename . '.php')) { 
            extract($data); // $data['apps'] is now exposed as $apps variable
            require_once '../view/' . $filename . '.php';
        }
    }
    

    THOUGH, your use of require_once could cause you problems. If a view is to be displayed twice on the same request, only the first call to view() will do anything. I'd replace require_once with require

    Unrelated Suggestion: I'm personally fond of early returns, instead of nesting meaningful code inside if blocks. I also like explicit pathing and types. You can ignore this suggestion, but I personally would write the method more like this:

    protected function view(string $filename, array $data = []) { 
        $file_path = __DIR__.'/../view/'.$filename.'.php';
        if (!file_exists($file_path))return;
        
        extract($data); // expose each array key as a variable.
        require $file_path;
    }