Extending CodeIgniter’s Database Forge Class

UPDATED 2/13: Added License (MIT) Info to code
UPDATED 1/13: Changed ‘required’ ‘required_once’ to avoid errors of redeclaring CI_DBforge

I am working on a project in CodeIgniter that requires use of the database forge class to create/modify/delete database tables. Because the project makes use of database transactions, creating tables with the MYISAM engine was not going to work. So I was faced with two choices: Make all the database creation, etc run by manual queries such as
CREATE TABLE `blah`...
or extend the dbforge class. After some tinkering about I finally managed to successfully do this. Here’s how:
(Note: I am using CI 2. This also assumes you are somewhat familiar with extending CI classes)

  1. Create a MY_Loader.php file in application/core (or open it if you already have one).
  2. If you had to create the MY_Loader file, paste the following:
    <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
    class MY_Loader extends CI_Loader {
    }
  3. Paste the following in your MY_Loader file:

    /**
    * Extend the Database Forge Class
    *
    * @access public
    * @author (Original) EllisLabs / (Extension) J Elmore
    * @license MIT
    * @version 1.0
    * @return string
    */
    function dbforge()
    {
    if ( ! class_exists('CI_DB'))
    {
    $this->database();
    }

    $CI =& get_instance();
    $class = 'CI_DB_'.$CI->db->dbdriver.'_forge';

    require_once BASEPATH.'database/DB_forge'.EXT;
    require_once BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge'.EXT;

    if( file_exists(APPPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge'.EXT) ) {
    require_once APPPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge'.EXT;
    $class = 'DB_'.$CI->db->dbdriver.'_forge';
    }

    $CI->dbforge = new $class();
    }

    This basically adds the code to find/include the extended class, and instantiate it

  4. Next you need to create some folders in your application directory. First, create the folder database. Then, within the database folder, you’ll need to create a drivers folder. Within the drivers folder you’ll need to create a folder for the database type (mysql, mssql, etc) you are using. Since I am using MySQL, I created a mysql folder. My folder structure, then, looked like this:

    application/
    -->database/
    ----->drivers/
    -------->mysql/
  5. In the driver folder you created (in my case, the mysql folder), create a file in the format _forge.php. In my case I created mysql_forge.php.
  6. Create your extended class:

    <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
    class DB_mysql_forge extends CI_DB_mysql_forge {
    }
  7. Have fun extending the functions! To get my tables to specifically create with the InnoDB engine I used the following code:

    /**
    * Modify _create_table to use InnoDB
    *
    * @access public
    * @author (Original) EllisLabs / (Extension) J Elmore
    * @license MIT
    * @version 1.0
    * @return string
    */
    function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists)
    {
    $sql = parent::_create_table($table, $fields, $primary_keys, $keys, $if_not_exists);

    $sql = rtrim($sql, ';');
    /* Should note here that I have a custom config file with the key/value pair to hold the
    default database engine to use */
    return $sql.' ENGINE='.config_item('database_engine').';';
    }

I tried simply extending the dbforge class but since all the magic happens in the driver classes it was necessary to extend the driver and modify the functions there. Also, I know there are ways to set the mysql server to default to InnoDB creation but since this project may be sold/released at some point it is easier to modify the CodeIgniter files than to try and provide instructions for something most people wouldn’t be able to or know how to do.

Bespin Theme for Geany IDE

I love the Bespin theme that can be found for Textmate, Notepad++, and Gedit. Recently I started using the Geany IDE (http://www.geany.org/) as it’s a lot lighter than Eclipse/Netbeans/etc.

I spent the better part of an afternoon using the Online Theme Editor found at (http://geany.pdarko.co.cc/filetypes/) to recreate (to the best of my abilities) this theme which can now be found at http://github.com/nerdmom/Geany-Bespin-Theme. Please note that I only changed a few of the file definition files as that was all I needed to work with. If you are using a language other than HTML, PHP, and Javascript you’ll have to visit the theme editor I linked to above and make the changes there.

Enjoy!

A Follow-Up on Kohana 3 & CodeIgniter 2 – The Flip Side

The other day I wrote about my experiences/opinions with Kohana 3 and CodeIgniter 2. I’ve received feedback from both sides of the debate, and want to share some follow up thoughts and some of (IMO) CI2′s downsides.

Shadowhand commented:

…This is typical of pretty much all programming tools. For example, look at Python right now… they have been on the 2.x series for a long time and 3.x is not backward compatible.

I will be the first to admit that Kohana has had development instability in the past, but 3.x is rock solid and has a real release process in place. Please help us by judging 3.x separately from other versions.

I should say that my basis for opinion on the “instability” of Kohana has been based on its rewrite between versions 2 and 3, and the rapidity in which those major versions came out. IIRC, the 2.3 series (when I first started dabbling with it) was released in the early-mid 2008, and the 3.0.x series started to become available in mid-late 2009. If I had written an app for release with 2.3 in late 2008 and then been faced with a rewrite a year later that would’ve cost quite a bit just in man hours just to learn the framework (again) and figure out a semi-painless way to migrate my existing code to work with a new code base. Not to mention rewriting docs for my users, and so on.

To be completely fair, CodeIgniter 2 has a lot of its own shortcomings. I previously mentioned the procedural helpers, and the fair bit of hacking required (for me) to get it working the way I want (usually involving modules and autoloading, which yes, are a core part of Kohana). Another thing that irks me with CI is how the config items are lumped into one huge array which can make it very difficult at times to ascertain which config file I got a variable from, not to mention the possibility of item name collisions. Usually to get around this I would simply prefix my custom config files with file_configitemname, but that’s not entirely helpful for the core config files.

And please, PLEASE don’t get me started on using “eval()” in the database class. I know it’s a bit of a workaround…and a lot of times I use my own class or Doctrine, but even so..

Stewart commented

…I do have a problem with how they went about it (they should of made it clear KO2 had no future, rather than stringing people on and a new version number doesn’t really make it clear it is really a new framework.

This sums up my feelings pretty well. From what I’ve been able to ascertain (looking through commits on github and such), the API has remained fundamentally the same in the latest series.

And perhaps, for me, that was it. I just want to know there is fundamental stability within the framework itself, without the worry that my code will have to be completely reworked every 12-16 months.

FWIW I do find developing with Kohana quite easy and fun, and if the recent fundamental stability holds out I may be singing a different tune.

I should also take a moment to thank both EllisLab and the Kohana dev team for putting the countless hours into developing these frameworks so I don’t have to! :)

Kohana 3 & CodeIgniter 2

For the last month or so I’ve been developing an app side-by-side with Kohana 3 and CodeIgniter 2 to see which framework fits my programming style better. Nothing terribly fancy; just a simple CMS.

I’ve been using frameworks to develop since 2006, back around CI 1.5.x. The differences between CI 1.7.x (the latest version as of this post) and CI 2.0 are negligible. My biggest nitpick comes with the helpers. I’m lazy and I’m also somewhat speed-conscious, which means I either need to autoload all the helpers my app needs in the autoload.php file (or early in my app) to appease my laziness, or load them as needed to appease my speed-consciousness. It irritates me that they’re basically files holding groups of procedural functions and if I want to access the CI super global I have to instantiate it in every function.

I started dabbling with Kohana a couple of years ago, in the 2.3.x era. I really loved their use of static functions (I’d only had basic OOP experience at the point), but I just never felt comfortable with the way things changed so much between versions. Last year when v3 was announced I had a look through the code and said “forget it”. But eventually I became curious again and started learning it to see how easy/hard it was to develop with it. I personally did not have a lot of trouble learning Kohana 3, between the user guide and the unofficial wiki. Perhaps my biggest stumbling block came with the Database module, which was a complete change from any of the v2.x database classes.

I really didn’t find either framework harder than the other to code for. I was able to more or less figure out how to do what I wanted to do in both. Yes, Kohana’s docs suck and CI’s are much better. For me it wasn’t much of an issue.

In the end it comes down to framework stability for me. And in this case, CI wins, hands down. Don’t get me wrong; Kohana is beautifully written and introduced me to a prime example of clean, well commented code. The devs are extremely intelligent and more talented than I’ll probably ever be. CI is also very clean, though there’s a bit more hacking involved for me to get it to work the way I like. However, I don’t want to be writing my own clean, well-commented code for one version of a framework only to find out the next version is going to totally break backwards compatibility. The lead Kohana devs have stated that there are no guarantees of stability between major versions (ie 1.x-2.x, etc). Comments like “well if it ain’t broke, don’t fix it” are dandy, but if part of the reason I’m using a framework is to let someone else worry about the basics for me, why would I stick with something that is no longer actively developed because the devs are on version 342.x?

While I respect progress and not letting code stagnate there’s something to be said for code stability when you’re maintaining a framework. Uber-optimising something is great (as there are repeated mentions of “x function is faster than w function” in the Kohana forums) but if it’s only saving me 0.02 ms of page load time or 0.25 mb memory, I’m not sure unstable code is worth that bit of extra speed. Furthermore, using an older codebase when you’re a one-(wo)man show can be a nightmare, since it’s a lot easier for one person to miss something than two, whether it’s a simple invalid method call or a glaring security hole.

I want to create apps to earn a living and I want to know that my code will stay more or less relevant between framework versions. API changes are to be expected between versions but complete rewrites, with very little thought for BC is just poor project management, IMO.

Please bear in mind that these are simply my views on the frameworks and my experiences and since I’m not a BDFL PHP guru (or something), you should perform your own research to see what works for you.

Update: I’ve posted a follow up post with some more thoughts (and such): http://nerdmom.wordpress.com/2010/08/31/a-follow-up-on-kohana-3-codeigniter-2-the-flip-side/

CakePHP 1.3, Smarty 3, and Theming. Woohoo!

There are various solutions out there for integrating Smarty with CakePHP. I’m here to introduce another one, that I feel is a little leaner than the other solutions I’ve found.

Jump to the code: https://gist.github.com/672398

Requirements:

  • Cake 1.3.2 (No idea if it will work on < 1.3.2)
  • Smarty 3

Just place this in your /app/views folder andmake sure your AppController has the following lines:

public $view = "Theme";
public $layout = "default";
// The following line is optional; the default ext in the ThemeClass is set to .html.
// Uncomment to set to your desired extension
// public $ext = ".some_extension";

Your views would (unless you change the $ext variable) then be saved with .html extensions.

CakePHP, Using Edit For Add/Edit Functions, & Plugins (Oh My!)

When I work on a project I usually combine my add/edit functions into just edit. This saves some space in my controllers and makes maintenance a lot easier as I have only one function to edit instead of 2.

To accomplish this in Cake, you’d just do something like this:
Router::connect('/:prefix/:controller/add', array('action' => 'edit', "admin" => true));
This will map your controllers in your “app/controllers” folder nicely.

But let’s say you’re building an app that includes plugins. You may think “Ha hah! I’ll just slap this in my routes.php file”:
Router::connect('/:prefix/:plugin/:controller/add', array('action' => 'edit', "admin" => true));
And it will work..kinda.

More specifically, it will work for the subcontrollers of your plugin. For example, if you have a news plugin, and the news plugin has a comments controller, the above route will work, because it will map “/admin/news/comments/add” to /admin/news/comments/edit”.

HOWEVER!! This will NOT work for the news controller itself
Dramatic Chipmunk

*ahem* Luckily, the fix is easy and only took me 2 days to figure out (hey, I have kids; things get put aside…yeah, that’s my reason)
Router::connect('/:prefix/:plugin/add', array('action' => 'edit', 'admin' => true));
Now you can access “/admin/news/add” as you’d expect!

Quick Little Tip Regarding Cakephp forms

Occasionally when I am coding something in Cake that requires a form, I run into a problem if I use something like

if( !empty($this->data) ) ...

If there is another method that posts to the URL that the above code rests on (an Auth class trying to preserve the page the person was trying to reach, for example), then chances are good the method will think the user is trying to post to that method as well.

Anyway, my quick solution to ensure that only the data *I* want is posted is this:

if( !empty($this->data['ModelName']) ) { ..

This ensures that the method is only looking for the data that we want to post to it.

New Source for Code Snippets

I’ve signed up at Github, and will from now on be posting code snippets and such there.

CodeIgniter + Smarty w/Layout Capabilities - http://gist.github.com/264823

Twilight

My sister is in her early 20′s and is a die-hard Twilight fan. She owns all 4 books and has been bugging me for months to read them. So last week she brought them over and yesterday I opened the first book and started reading.

Now, I should mention that when it comes to ultra-popular fads I tend to stay far back until some of the hubub dies down. I didn’t start reading Harry Potter until my sister took me to see the first movie. And I’d heard pretty horrible things about the Twilight series anyway, in terms of literary-ness.

I was surprised to find that I did enjoy the story, enough to finish reading the first book in one day. I liked the ideas (most of them – I mean, sparkly vampires..C’MON!! lol) and the basic premise of it all.

That being said..

The writing is horrid. I’m sorry if I offend any fans out there, but I can’t believe that the book was published the way it was. I couldn’t turn around without tripping over a cliche. The main character, Bella, was flat and boring. She seemed to have no desires to do anything outside of be with Edward. She seemed to have no interests, nothing. She seemed whiny and a complete doormat to anyone around her.

And what did the author do, pull out a thesaurus to use as many $0.50 words as possible? I started outlining a drinking game to take a drink every time Bella described one of Edward’s features as “marble”, only to realize it would likely end up giving someone alcohol poisoning.

Don’t get me wrong – I really did like the premise of the book and the story itself. I just felt that it was really badly executed. If they went back and revised it a couple of times I think it would be a very compelling and powerful book.

Just my opinion, though.

Custom Error Handling in CakePHP when debug = 0

Not sure if this is the most correct way to handle this, but I wanted to use a custom error method in my controllers. However, if you’ve been working with CakePHP a bit, you’ll notice that Cake automatically throws a 404 error when you set debug to 0.

To get around this I opened up /cake/libs/error.php and commented out the following lines:

/*if (Configure::read() == 0) {
$method = 'error404';
if (isset($code) && $code == 500) {
$method = 'error500';
}
}*/

This seems to solve the problem, for now. Hopefully this will be fixed in a future version of Cake because I detest modifying core files.

Follow

Get every new post delivered to your Inbox.