Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CodeIgniter (pre-controller) hooks and caching

Summary:

Do pre-controller hooks execute during caching? Is there any hook-point which will execute? (pre-system?)

I should probably highlight the fact that the hook doesn't affect the content that is sent to the browser. That isn't an issue.


Detailed version:

I plan on implementing some statistics-type functionality in a project I've built using PHP and CodeIgniter.

The project in question is a custom built CMS - due to the extended intervals between updates I've used caching to help speed up load times; this isn't essential but it's preferential. It seems to be a good solution to a largely static site; especially where dynamic content is primarily served client-side - i.e AJAX requests.

The proposed functionality primarily involves a pre-controller hook which accesses methods through libraries such as the User Agent library, before dumping them to a database. From here it can be polled, outputted via JSON and manipulated before being displayed by something like the jQuery flot plugin.

I've read through the documentation on the Web Page Caching as well as the documentation regarding hooks. Unfortunately, it's still not clear whether using caching will completely bypass the hooks.

I'm aware of the cache_override however this means implementing your own caching mechanism; not what I want to do!

The alternative would be gathering statistics client side and submitting it to the server via AJAX; but this isn't ideal either as I'm trying to have a clear separation of logic - for maintenance and testing reasons.

like image 582
Fergus In London Avatar asked Dec 07 '12 21:12

Fergus In London


1 Answers

In short:

  • Do pre-controller hooks execute during caching? No.
  • Is there any hook-point which will execute? Yes pre_system does execute.

If caching kicks at system/core/CodeIgniter.php:189, the only hook that gets a chance to run is pre_system (system/core/CodeIgniter:124).

Unfortunately you don't get much functionality of codeigniter at that point, no get_instance() and without that most core libraries are not loaded as well. If you are inclined you can look into what functions are defined inside system/core/Common.php thats pretty much all you got.

If you are really want to make this work with the built in classes you can sort of fight your way to a database object and other core stuff like this:

  1. You will have to manually get the BASEPATH.'database/DB.php' file included in. Fortunately in the loader class, it loaded with require_once so it won't break the page on cache miss.
  2. Once you got the Database library loaded instantiate the usual $this->db object with calling DB(). Without parameters it will load the default database from the config files as usual.
  3. At this point you can write your queries from your pre_system hook, and since hooks can be objects, you can move every logging code inside the hook's object. If you need other libraries you can get an instance of them with the load_class() function (don't forget to set the third prefix parameter to empty string if you are not loading a built in class).

At the end you should end up like this (imaginary code):

class MyLoggingHook {
    // called from the hook config
    public function run($params = array()) {
        require_once(BASEPATH.'database/DB.php');
        $db = DB(); // getting hold of a DAO instance

        // routing information is always useful to have for pageview logs
        $RTR = load_class('Router', 'core');
        $RTR->_set_routing();
        // Router also load Uri and Config classes inside so the following two instances could be interesting too:
        // $RTR->uri 
        // $RTR->config

        // load some useful library not related to CodeIgniter
        $user_agent_detector = load_class('UserAgentDetector', 'libraries', '');

        // do some logging
        $db->insert('page_view_log', array('class' => $RTR->fetch_class(), 'method' => $RTR->fetch_method(), /*...*/);
    } 
}

I should probably mention that i've never used something like this in production and there's the risk of relaying on funcionality that could change from version to version. If you can do without touching the Codeigniter classes inside your hook go with that.

Using PDO for database access, loading the database config with get_config(), you can get by without touching any codeigniter related classes.

like image 115
complex857 Avatar answered Sep 24 '22 14:09

complex857