Ray
Ray

Reputation: 780

PHP fat free framework using $this when not in object context?

I am developing a project using fat free PHP framework. In the documentation, they said you can build your own skeleton for the project, so my project directory is like the following:

in the index.php I am calling the framework (controllers and models including the database connection) and having my routes as the following:

// Kickstart the framework
$f3=require($_SERVER['DOCUMENT_ROOT'] . '/project_name/lib/base.php');
$f3->set('AUTOLOAD',''.$_SERVER['DOCUMENT_ROOT'] . '/project_name/controllers/; '.$_SERVER['DOCUMENT_ROOT'] . '/project_name/models/');

$f3->set('DEBUG',3);
if ((float)PCRE_VERSION<7.9){
    trigger_error('PCRE version is out of date');
}

if (!($f3->get('DEBUG')))
{
    $f3->set('ONERROR',
        function($f3) {
                $f3->reroute('/');
        }
    );
}

/****************** Start Routing the URLs ******************/

/****** Home Controller ******/
$f3->route('GET|HEAD /',
    function($f3) {
        $f3->reroute('/home');
    }
);

$f3->route('GET|HEAD /index',
    function($f3) {
        $f3->reroute('/home');
    }
);

$f3->route('GET /home','Controller_Home->main');

$f3->run();

inside Model.php I have a function that connect successfully to the database that I have like the following:

class Model
{
    public $f3, $db;

    public function connect()
    {   
        global $db;

        $username = 'username';
        $password = 'password';
        $hostname = 'hostname';
        $dbname = 'dbname';

        try{
            $db = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        catch(PDOException $e){
            echo $e->getMessage();
        }
        print_r($db); // this will give PDO Object ( )
        $this->db = $db;
    }
}
// if you try to execute query here, it will work.

Now, in Controller.php I am calling the connect() function in Model.php inside the construct like the following:

class Controller extends Model
{
    public $f3, $db;

    public function __construct($f3)
    {
        $this->f3 = $f3;
        $this->connect();
    }   
}

Model_Home.php has functions that queries the database like the following:

class Model_Home extends Model
{
    public $f3, $db;

    public static function getUsers()
    {
        $query = "SELECT * FROM users";
        $result = $this->db->query($query);
        $output = '';
        while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
            $output.= '<tr>
                            <td>'.$row['attrib1'].'</td>
                            <td>'.$row['attrib2'].'</td>
                            <td>'.$row['attrib3'].'</td>
                            <td>'.$row['attrib4'].'</td>
                            <td>'.$row['attrib5'].'</td>
                      </tr>';
        }

        return $output;
    }
}

and Controller_Home.php will call the previous function statically and then call the right view to render the result like the following:

class Controller_Home extends Controller
{
    public $f3, $db;

    public function main($output = '')
    {
        //setting up the variables
        $this->f3->set('getUsersTable', Model_Home::getUsers());
       // getUsersTable is a variable that will be passed to the view to reder

        //calling the view
        $this->f3->set('main','views/home/main.html');
    }
}

The last thing is the main.html page which is like the following:

<h1>All Users</h1></br>
<?php echo htmlspecialchars_decode($getUsersTable); ?>

when I run the code, it will give me an error message says: Fatal error: Using $this when not in object context

project_name/models/Model_Home.php:8

which refers to the following line in Model_Home.php

$result = $this->db->query($query);

the php version that I have to use is 5.4 (pretty old). Any idea, please!

Thanks everyone!

Upvotes: 0

Views: 1802

Answers (2)

Daniel
Daniel

Reputation: 35684

Firstly, get a little more familiar with f3 before trying to create this kind of skeleton. The code you have posted seems to indicate that there are a couple key concepts that you can make good use of that you may not be familiar with.

Use templates call the template from controller using echo \Template::instance()->render('templates/controller_index.htm');

Use F3 ORM Though somewhat limited compared to some other ORMs such as Eloquent, the F3 ORM does speed up dealing with the database. read up on it here: http://fatfreeframework.com/databases

$user=new DB\SQL\Mapper($db,'users');
$user->load(array('userID=? AND password=?','cheetah','ch1mp')); // load one user
$allusers = $user->find(); // get all users

Based on the model code you have, I would say you can get away without using any Models at all, using the Mapper class can take you a long way.

store configuration in a config file. This will separate the configuration information from the logic.

$f3->config("config.ini");

Any value defined there can be accessed like a global

[globals]
DEBUG=0
CACHE=true

; Database
db.host=localhost
db.port=3306
db.user=root
db.pass=
db.name=phproject

; Session lifetime
; Also set session.gc_maxlifetime in php.ini
JAR.expire=604800

like so...

// Connect to database
$f3->set("db.instance", new DB\SQL(
    "mysql:host=" . $f3->get("db.host") . ";port=" . $f3->get("db.port") . ";dbname=" . $f3->get("db.name"),
    $f3->get("db.user"),
    $f3->get("db.pass")
));

If you put that code in your index file before you call any controller, you can call your database connection easily. using $f3->set("db.instance",...) you create and set the connection

// get reference to instance and initialize mapper
$user = new DB\SQL\Mapper($f3->get("db.instance"),'users');

// get all records (same as SELECT * FROM $tablename) and put them inside all_users var
$f3->set('all_users', $user->find());

if you then use this information in your template file, you'd do something like this

<table>
<repeat group="{{ @all_users }}" value="{{ @user }}">
    <tr>
        <td>{{ @user.attrib1 }}</td>
        <td>{{ @user.attrib2 }}</td>
        <td>{{ @user.attrib3 }}</td>
    </tr>
</repeat>
</table>

Upvotes: 3

sg-
sg-

Reputation: 2176

You have defined Model_Home::getUsers as a static method. This means it is a method of the class and not the instantiated object, which in turn means you don't get access to object properties, only class properties and methods defined as "static" . $db is not defined as "static" and therefore it's a property of the object and not the class.

If you want to keep getUsers as static:

You can either define $db as "static" (which will require other code changes for any code that references it), or use the Singleton pattern whereby an instance of an object is stored as a static class variable for access by other class methods. Eg:

class myClass
{
    protected static $db = null;

    public static function getDb()
    {
        if(empty(self::$db))
            self::$db = new Database();

        return self::$db;
    }
}

If you don't care about keeping getUsers static:

Just remove the "static" keyword from its declaration, and you will also have to update this method call from:

$this->f3->set('getUsersTable', Model_Home::getUsers());

to:

$modelHome = new Model_Home;
$this->f3->set('getUsersTable', $modelHome->getUsers());

Upvotes: 0

Related Questions