Jump to content

Fatal error: Call to a member function where() on a non-object


RalphLeMouf

Recommended Posts

Hello -

 

I am fairly new to codeigniter, and it's been about a week now being stuck with this error. I have watched video tutorials, read copious amounts of related questions on other forums, and tried about 10 different methods and continue to get this error. I have hit a wall and really need help. I've tried loading the my database manually and with the auto-helper as well as trouble shooting my config files and such. please help!

 

Here is my current MVC set up for trying to login a user:

 

MODEL:

 

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class User_model extends CI_Model {
    function __construct(){
        parent::__construct();
    }

    public function validate(){
        // grab user input
        $email = $this->security->xss_clean($this->input->post('email'));
        $password = $this->security->xss_clean($this->input->post('password'));

        // Prep the query
        $this->db->where('email', $email);
       	$this->db->where('password', $password);

        // Run the query
        $query = $this->db->get('users');
        // Let's check if there are any results
        if($query->num_rows == 1)
        {
            // If there is a user, then create session data
            $row = $query->row();
            $data = array(
                    'id' => $row->id,
                    'first_name' => $row->first_name,
                    'last_name' => $row->last_name,
                    'validated' => true
                    );
            $this->session->set_userdata($data);
            return true;
        }
        // If the previous process did not validate
        // then return false.
        return false;
    }
}
?>

 

VIEW:

 

 

<title>Login</title>

<!--MAKE SURE SIGNED OUT HEADER IS IMPLEMENTED FOR ALL SIGNED OUT PAGES INCLUDING THIS ONE-->

<div class="structure clearfix">
<h1 class="title_header">
	Sign In
</h1>
<div id="signin_form">
	<?php
	echo validation_errors(); 
	echo form_open('auth/process');
	echo "<div class='form_text_signin'>";
	echo "Email";
	echo "</div>";
	echo form_input('email');
	echo "<div class='form_text_signin'>";
	echo "Password";
	echo "</div>";
	echo form_input('password');
	echo form_submit('submit', 'Submit');
	echo form_close();
	?>
</div>
</div>

 

 

CONTROLLER:

 

<?php
class Auth extends CI_Controller {

// this is automatically called if no other function is called
// it simply turns around and calls the login() function to show the login page

public function index($msg = NULL) {
	$data['msg'] = $msg;
	$this->login();
}

function __construct() {
        parent::__construct();
}

public function login() {	
$data['main_content'] = 'auth/login';
$this->load->view('includes/templates/main_page_template', $data);

}
    public function process(){
        // Load the model
        $this->load->model('user_model');
        // Validate the user can login
        $result = $this->user_model->validate();
        // Now we verify the result
        if(! $result){
            // If user did not validate, then show them login page again
            $this->index();
        }else{
            // If user did validate,
            // Send them to members area
            redirect('account/dashboard');
        }
    }

}

 

thanks so much in advance

 

 

 

 

 

Link to post
Share on other sites

[*] You don't need to use $this->security->xss_clean() in your models, you should enable it by default in config/config.php under $config['global_xss_filtering'].

While you're in your config, set logging to 4 and refresh your page.  If you check your logs/ folder, you should have a debug dump that explains what gets loaded and what fails. If you do not have this file, make sure it's writable by the apache server.  Be sure to put it back to 0 when you're done, or you'll have a helluva mess in your logs dir.

 

[*] You're setting your session object as a 2d array. 

This is likely what's causing the error.  The correct way to set session data is $this->session->set_userdata('item', 'value'); where it can be retrieve / compared with like thus: echo $this->session->userdata('item');

 

[*] You are calling a CI method before you are instanciating the class. 

Move your public function index() below the function __construct()

 

[*] Your view is poorly written more coherency could be applied to your fieldset

<?php
    echo form_open('auth/process');

    echo form_label('Email Address', 'email', array('class'=>'form_text_signin'));
    $data = array( 'name' => 'email', 'class' => 'input', 'size' => 30 );
    echo form_input($data, set_value('email'));

    echo br();
...
    $data = array('name' => 'login', 'class' => 'submit', 'value' => 'Log In');
    echo form_close();

Obviously, this has nothing to do with your error. It just makes my skin crawl to see needless echos for HTML.

 

Make some adjustments and let us know what you get back.  If the CI logs don't give you anything to lead you, check your apache error logs.

Link to post
Share on other sites
You are calling a CI method before you are instanciating the class.

 

Move your public function index() below the function __construct()

 

The order in which methods are added to a class is irrelevant.

Link to post
Share on other sites

Ok - I went ahead and simplified my approach back to the original way I had it based off of a code igniter tutorial video I watched. I have set the log threshhold to 4 and have scoured through all the different ways to view the error logs and am not seeing any relavent clues.

 

Here is what the log is telling me: Please note that I reload the page and after trying to submit the form and the same results keep coming up in the log. Nothing new.

 

[Mon Jul 09 08:36:11 2012] [notice] Digest: generating secret for digest authentication ...

[Mon Jul 09 08:36:11 2012] [notice] Digest: done

[Mon Jul 09 08:36:11 2012] [notice] Apache configured -- resuming normal operations

 

( note that these are from yesterday and not this morning )

 

Here is the simplified MVC I've reverted back to. I will go through the view later and simplify the html, as I have to work it to my styles and am more concerned with resolving the major issue at hand first.

 

MODEL:

 

<?php

 

class User_model extends CI_Model {

function validate () 
{
	$query = $this->db->where('email', $this->input->post('email'));
	$query = $this->db->where('password', sha1($this->input->post('password')));
	$query = $this->db->get('users');

	if($query->num_rows == 1)
	{
		return true;
	}
}
}

 

VIEW:

 

<title>Login</title>

<!--MAKE SURE SIGNED OUT HEADER IS IMPLEMENTED FOR ALL SIGNED OUT PAGES INCLUDING THIS ONE-->

<div class="structure clearfix">
<h1 class="title_header">
	Sign In
</h1>
<div id="signin_form">
	<?php
	echo validation_errors(); 
	echo form_open('auth/validate_credentials');
	echo "<div class='form_text_signin'>";
	echo "Email";
	echo "</div>";
	echo form_input('email');
	echo "<div class='form_text_signin'>";
	echo "Password";
	echo "</div>";
	echo form_input('password');
	echo form_submit('submit', 'Submit');
	echo form_close();
	?>
</div>
</div>

 

CONTROLLER:

 

 

<?php
class Auth extends CI_Controller {

// this is automatically called if no other function is called
// it simply turns around and calls the login() function to show the login page

public function index() {

	$this->login();
}

public function login() {	
$data['main_content'] = 'auth/login';
$this->load->view('includes/templates/main_page_template', $data);

}

function validate_credentials () {
	$this->load->model('user_model');
	$this->user_model->validate();


	if($query)
	{
		$data = array(
			'email' => $this->input->post('email'),
			'password' => $this->input->post('password'),
			'is_logged_in' => true
		);

		$this->session->set_userdata($data);
		redirect('account/dashboard');
	}
	else
	{
		$this->index();
	}
}
}

 

 

 

Link to post
Share on other sites

*edit* in my model I got rid of

$query = 

before 

$this->db->where('email', $this->input->post('email'));$this->db->where('password', sha1($this->input->post('password')));

 

Makes sense.  You can further simplify your queries without needing to recall the object like so:

 

controller

<?php
$data = array(
    'email' => $this->input->post('email'),
    'password' => sha1($this->input->post('password'),
);
$this->model_name->login($data);

 

model

<?php
function login($data = array())
{
// validate data
if( !empty($data) ) return FALSE;

// retrieve query
$query = $this->db
        ->from('users')
        ->where($data)
        ->get();

// Check if query row exists
if($query->row())
{
    // Query row exists, return query row
    return $query->row();
}
else
{
    // Query row doesn't exist, return FALSE
    return FALSE;
}

Link to post
Share on other sites

thanks for the help.

 

This is the error I got from your suggestions

 

Call to undefined method User_model::validate() in /Users/michaelsanger/Sites/CodeIgniter/application/controllers/auth.php on line 20

 

Here is how the whole package looks according to your adjustments:

 

MODEL:

 

<?php

 

class User_model extends CI_Model {

function login($data = array())
{
// validate data
if( !empty($data) ) return FALSE;

// retrieve query
$query = $this->db
        ->from('users')
        ->where($data)
        ->get();

// Check if query row exists
if($query->row())
{
		return true;
	}
}
}

 

CONTROLLER:

 

 

<?php
class Auth extends CI_Controller {

// this is automatically called if no other function is called
// it simply turns around and calls the login() function to show the login page

public function index() {

	$this->login();
}

public function login() {	
$data['main_content'] = 'auth/login';
$this->load->view('includes/templates/main_page_template', $data);

}

function validate_credentials () {
	$this->load->model('user_model');
	$query = $this->user_model->validate();


	if($query)
	{
		$data = array(
			'email' => $this->input->post('email'),
			'password' => $this->input->post('password'),
		);

		$this->user_model->login($data);
		redirect('account/dashboard');
	}
	else
	{
		$this->index();
	}
}
}

 

 

Link to post
Share on other sites

also more information from my error logs:

 

mysql portion ( apache portion listed above)

 

120709 08:35:59 mysqld_safe Starting mysqld daemon with databases from /Library/Application Support/appsolute/MAMP PRO/db/mysql

120709  8:35:59 [Warning] The syntax '--skip-locking' is deprecated and will be removed in a future release. Please use --skip-external-locking instead.

120709  8:35:59 [Warning] Setting lower_case_table_names=2 because file system for /Library/Application Support/appsolute/MAMP PRO/db/mysql/ is case insensitive

120709  8:35:59 [Note] Plugin 'FEDERATED' is disabled.

120709  8:35:59 [Note] Plugin 'ndbcluster' is disabled.

120709  8:36:03  InnoDB: Started; log sequence number 0 44273

120709  8:36:03 [Note] Event Scheduler: Loaded 0 events

120709  8:36:03 [Note] /Applications/MAMP/Library/libexec/mysqld: ready for connections.

Version: '5.1.44'  socket: '/Applications/MAMP/tmp/mysql/mysql.sock'  port: 3306  Source distribution

 

Link to post
Share on other sites

The error is telling you your model does not have that function ( validate() ). 

 

CI calls methods the functions inside your classes.

 

You're not actually accomplishing anything at all with your code.

 

[*]Your view has two fields: email and password.

[*]Your controller receives the submission and preps the data - then passes it to the model.

[*] Based off of the returned data you go forth with your intentions.

 

If you look at my last post, I described exactly how to take the form input and submit it to the model

Link to post
Share on other sites

ok so to be clear here:

 

your saying I should get rid of the validate_credentials() function currently in my controller and put :

 

 

<?php
$data = array(
    'email' => $this->input->post('email'),
    'password' => sha1($this->input->post('password'),
);
$this->model_name->login($data);

 

inside the login () function with what is already existing?

 

With that being said. This is what I currently have trying to adapt it to your suggestions.

 

MODEL:

 

<?php

class User_model extends CI_Model {

function login($data = array())
{
// validate data
if( !empty($data) ) return FALSE;

// retrieve query
$query = $this->db
        ->from('users')
        ->where($data)
        ->get();

// Check if query row exists
if($query->row())
{
    // Query row exists, return query row
    return $query->row();
}
else
{
    // Query row doesn't exist, return FALSE
    return FALSE;
}

 

CONTROLLER:

 

 

<?php
class Auth extends CI_Controller {

// this is automatically called if no other function is called
// it simply turns around and calls the login() function to show the login page

public function index() {

	$this->login();
}

public function login() {	
$data['main_content'] = 'auth/login';
$this->load->view('includes/templates/main_page_template', $data);

}

function validate_credentials () {
	$this->load->model('user_model');
	$this->user_model->validate();


	if($query)
	{
		$data = array(
			'email' => $this->input->post('email'),
			'password' => $this->input->post('password'),
			'is_logged_in' => true
		);

		$this->session->set_userdata($data);
		redirect('account/dashboard');
	}
	else
	{
		$this->index();
	}
}
}

 

Sorry this is so difficult. I am just very new at this MVC framework. Thanks!

 

Link to post
Share on other sites

Making progress! With what I currently have, I've avoided the error! It just reloads the form with "/validate_credentials" tacked on to the end of the url. It looks like it's doing it's job by reloading the page if the info the user put in is not validated. Now it seems like a database issue. Here is what I have.

 

Model:

 

<?php

class User_model extends CI_Model {

function login($data = array())
{
// validate data
if( !empty($data) ) return FALSE;

// retrieve query
$query = $this->db
        ->from('users')
        ->where($data)
        ->get();

// Check if query row exists
if($query->row())
{
    // Query row exists, return query row
    return $query->row();
}
else
{
    // Query row doesn't exist, return FALSE
    return FALSE;
}
  }
}

 

View:

 

<title>Login</title>

<!--MAKE SURE SIGNED OUT HEADER IS IMPLEMENTED FOR ALL SIGNED OUT PAGES INCLUDING THIS ONE-->

<div class="structure clearfix">
<h1 class="title_header">
	Sign In
</h1>
<div id="signin_form">
	<?php
	echo validation_errors(); 
	echo form_open('auth/validate_credentials');
	echo "<div class='form_text_signin'>";
	echo "Email";
	echo "</div>";
	echo form_input('email');
	echo "<div class='form_text_signin'>";
	echo "Password";
	echo "</div>";
	echo form_input('password');
	echo form_submit('submit', 'Submit');
	echo form_close();
	?>
</div>
</div>

 

Controller:

 

<?php
class Auth extends CI_Controller {

// this is automatically called if no other function is called
// it simply turns around and calls the login() function to show the login page

public function index() {

	$this->login();
}

public function login() {	
$data['main_content'] = 'auth/login';
$this->load->view('includes/templates/main_page_template', $data);

}

function validate_credentials () {
$query = $this->load->model('user_model');

	if($query)
	{
		$data = array(
			'email' => $this->input->post('email'),
			'password' => $this->input->post('password'),
			'is_logged_in' => true
		);

		$this->session->set_userdata($data);
		redirect('account/dashboard');
	}
	else
	{
		$this->index();
	}
}
}

Link to post
Share on other sites

You are almost there.  Let's start from the beginning and explain how we are getting there.

 

Your users need a place to log in, enter the first controller

controller( account )

<?php
class Account extends CI_Controller {

/**
 * Constructor
 */	
function __construct()
{
	// Call the Controller constructor
	parent::__construct();
	// Load controller global models, libraries, helpers, and hooks
}
...
function login()
{
// determine if the user is signed in with their session data

// user is signed in, redirect to account dashboard

// user is not signed in, load the view
}

 

Now build the login page

views/login.php

<title>Login</title>
<div class="structure clearfix">
<h1 class="title_header">
	Sign In
</h1>
<div id="signin_form">

<?php
    // set the path for the form to process to
    echo form_open('auth/process');

    // create a label, dataset, and the input for email address
    echo form_label('Email Address', 'email', array('class'=>'form_text_signin'));
    $data = array( 'name' => 'email', 'class' => 'input', 'size' => 30 );
    echo form_input($data, set_value('email'));

    // create a label, dataset, and the input for the password
    echo form_label('Password',  'password', array('class'=>'form_text_signin'));
    $data = array( 'name' => 'password', 'class' => 'input', 'size' => 30 );
    echo form_password($data, set_value('password'));

    // now create the dataset for the submit button
    $data = array('name' => 'login', 'class' => 'submit', 'value' => 'Log In');
    echo form_submit( $data );

    // close the form
    echo form_close();
?>
</div>
</div>

 

CI lets you build all your form datas through their form_helper which I find extremely useful.  Also, when you create the form through the helper a hidden CSRF field is added for extra security.  Anyway, off to the auth controller.

 

controller (auth)

<?php
class Auth extends CI_Controller {
/**
 * Constructor
 */	
function __construct()
{
	// Call the Controller constructor
	parent::__construct();
	// Load controller global models, libraries, helpers, and hooks
}

// this is automatically called if no other function is called
// it simply turns around and calls the login() function to show the login page

function index() { // There is no real need to classify this controller as public

	$this->login();
}

function login()
{	
	// catch the form submitted from login
	$login = $this->input->post('login');

	// if the login form was submitted, let's play with the data
	if( $login ) {
		// you will want to set some validation data for the inputs
		// let's just call it required for now, you can read up on this stuff later
		$this->form_validation->set_rules('email', 'Email', 'trim|required');
		$this->form_validation->set_rules('pass', 'Password', 'trim|required');

		// Form validation passed, so continue
		if ( !$this->form_validation->run() == FALSE )
	{
		// now you can create your dataset
		$data = array(
		'email' => $this->input->post('email'),
		'password' => sha1($this->input->post('password')),
		);

		// now take that array and pass it to the model
		// since we don't need the data on this page, we're going to
		// either refresh the page, or redirect to the homepage / account dashboard
		// we do this by determining if our handshake was successful or not

	if( !$this->user_model->login($data) )
		{
			// login failed, alert user we can fail validation directly so that the form 
			// repopulates with their previous data using set_value('field_name')
			$this->form_validation->set_message('login_failed', 'Invalid credentials');
		}
		else
		{
			// user logged succesfully
			redirect('dashboard');
		}
	}
}

 

 

So we did many things there, most importantly we sent the form data to the model which will now process the information and determine the fate of the form

model (user_model)

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 

class Users_model extends CI_Model {

/**
 * Constructor
 */
function __construct()
{
	// Call the Model constructor
	parent::__construct();
}

function login( $data = array() );
{
	// check for data.  if the form is empty, the login req's are not met
	if( empty($data) ) return FALSE;

	// retrieve query
	$query = $this->db
	        ->from('users')
	        ->where($data)
	        ->get();

	// Check if query row exists.  The existence is enough to validate our query
	// which means the user logged succesfully.  Now we can set our session data
	if($query->row())
	{
	    // Now we have access to the user's table data and can set our session
	   $this->session->set_userdata('id', $query->row()->id);
	   $this->session->set_userdata('first_name', $query->row()->first_name);
	   ...
	   // now return TRUE for the controller to know what to do
	   return TRUE;
	}
	else
	{
	    // Query row doesn't exist, return FALSE
	    return FALSE;
	}
}

 

That's how I ensure the separation of powers between the MVC, and it's worked well for me. 

 

 

 

 

Link to post
Share on other sites

Is this impossible to do with just the 3 pages I have? It seems like I should be able to without adding that additional first controller you mocked up

Of course, i was only simulating based off of how i read your auth controller - it didn't appear to serve the login page.

Link to post
Share on other sites

I've done some trouble shooting using

$this->output->enable_profiler(TRUE);

That being said. The post data is correct but under the query section I'm getting

Database driver is not currently loaded

. It appears that I'm passing and picking up the data correctly. Just having an issue with my database

Link to post
Share on other sites

I thought it was correct. I guess I thought wrong:

 

$active_group = 'default';

$active_record = TRUE;

 

$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root';
$db['default']['password'] = 'root';
$db['default']['database'] = 'cysticlife_CI';
$db['default']['dbdriver'] = 'mysql';
$db['default']['dbprefix'] = '';
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = '';
$db['default']['char_set'] = 'utf8';
$db['default']['dbcollat'] = 'utf8_general_ci';
$db['default']['swap_pre'] = '';
$db['default']['autoinit'] = TRUE;
$db['default']['stricton'] = FALSE;

Link to post
Share on other sites

i cannot replicate your issue. i've even tried an empty CI install and the db object loads properly.  i'm at a loss to why your object is being created by no properties set.  :confused: are you using a current CI version? do you have access to apache logs?

Link to post
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.