CodeIgniter, Me Myself And I, Today's Aha-Erlebnis

Zen In Code

The following bit, although on the rather shallow topic of writing computer code, rings true on a great many non-computer related levels.

Take note:

Models that will be used consistently on all the site's pages are best autoloaded in the
config/autoload.php file. Models that are used throughout all the methods of a controller, should be loaded in that controller's constructor. Models that are only needed in certain methods within a controller, should be loaded inside those methods, only.

— From CodeIgniter Optimization.

Standard
Books, CodeIgniter

Dead Trees

Couple of days ago I ordered a book on programming, and opted for the paperback (dead tree) version. The book was delivered to my home within two days.

People who opted for the digital download edition however, have yet to receive their download link, and are slamming the author for the faulty checkout routine... which the author himself programmed.

So now I'm not so sure whether I should trust the programming techniques as described by the author in his book.

Irony eh?

Standard
CodeIgniter, Today's Aha-Erlebnis, Web, Work

$this->lang /* FAIL */

Note to self: when dealing with a multi-language site, in a CodeIgniter extended class constructor, do not attempt this:


protected $lang;
function __construct() {
parent::__construct();
$this->lang = $this->uri->segment(1);
}

Instead you will want to do this:


	protected $language;
	function __construct() {
		parent::__construct();
		$this->language = $this->uri->segment(1);
	}

See what I did there? 'lang' to 'language'.

As it happens $this->lang, when in a CI constructor, will name-conflict with any native CI system library that needs to tap into something similar to $CI =& get_instance(), with a subsequent $CI->load->lang('some_library') call.

Thank me not.

Standard
CodeIgniter, Lucas, Music, Today's Aha-Erlebnis

Today’s Aha-Erlebnis

  • There's a second, optional argument to CodeIgniter's uri segment helper which allows for a fall back default in cases where the uri segment returns false:
    $this->uri->segment(2, date('Y'));
  • When loading a CI view, there's an optional third argument which, when set to true, allows you to assign the view to a variable, instead of directly outputting it to the browser. Very very handy when constructing RSS feeds, PDF-downloads, or html emails:
    //mail config...
    $msg = $this->load->view('email_template', $data, TRUE);
    $this->email->message($msg);
    $this->email->send();
  • At age two and a half my son is a confirmed, certified Apple nerd (do disregard Khadaffi audio in the back):

  • Today's favorite Beatles tune has to be Golden Slumbers.
Standard
CodeIgniter, Today's Aha-Erlebnis, Web, Work

CodeIgniter’s Cart Class With Accented Characters

This has bit me in the ass one too many times, so I thought I'd do a quick write-up of how I deal with CodeIgniter's otherwise wonderful Cart class and its refusal to accept accented "foreign" characters.

Important: The following assumes you are using PHP5+ and CI 2.0 or newer.

The problem

You have your product pages all nicely set up with an "Add to Basket" button. When that button gets clicked, via some jQuery $.get magic in my set-up, the product and its specifications gets added to the Cart object. If however your product's name has any accents in it (e.g. "Verre à Bière"), CodeIgniter will by default silently refuse to add that product to the cart.

The solution

Create a file in application/libraries and call it "MY_cart.php". In that file, paste the following code:

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

class MY_Cart extends CI_Cart {
    function __construct() {
        parent::__construct();
        $this->product_name_rules = '\d\D';
    }
}

This will override CodeIgniter's default set of allowed characters, and extend it with whatever accent you can think of. If you're not using Javascript to add items to the cart, that should do the trick and you can stop reading now.

However, as mentioned, I'm using jQuery's $.get method to add items to the cart, so that the page doesn't have to reload each time an item gets added (it's what the cool kids refer to as "Ajax"). Here's an example of the script I'm using for this:

$(function(){
	$('#addButton').click(function(){ 
		$.get("path/to/add_to_cart",
		{   
			id: $('input[name=id]').val(), 
			name: $('#name').val(), 
	   		qty: $('#qty').val(),
		       	price_option: $('#price_option').val()
		 }, 
		 function(data) {	
			$('#addedMsg').html(data.html).show();
			}, 'json'
		); // end get
		return false;   
	});		
});

Notice that I'm passing on the value of a hidden formfield with id "name" to this function. Now, here's the pitfall: Javascript will convert accented characters to their equivalent Unicode string (while, for legacy reasons, I'm having to use the iso-8859-1 charset). As a result, CodeIgniter will gladly add my item to its cart, but since it's passed through Javascript, the accented characters come out as "gibberish", once you have to display them in your cart view.

The solution here is to pass the regular product name (accents and all) to the jQuery function, and then do the following in the php script which actually adds the item to the cart. Instead of something like:

$data['name'] = $this->input->get('name');
//proceed to insert in cart

Do this:

//run the name variable through the ascii_to_entities() function
$data['name'] = ascii_to_entities($this->input->get('name'));
//proceed to insert in cart

Note that for this you will have to have CodeIgniter's Text helper loaded.

Almost there

What we've accomplished so far: CodeIgniter's Cart class accepts our accented product names, and although we've passed the names through Javascript, the correct characters still show up within the Cart object. But how about displaying items in a cart overview? If you link back each item to its product page, you will have to construct that link such that it re-instates the ascii characters instead of their respective entities:

base_url().'/controller/'.sanitize_title_dashes(entities_to_ascii($items['name']));

Note that I'm using sanitize_title_dashes() (see the WordPress core) as a method to obtain URL's which are restricted to an "a-z0-9" realm of characters - thereby omitting any characters that had previously been turned into entities! Using entities_to_ascii() allows them back into the url. Phew.

Wrapping up

While it may look a bit messy, the above solved the problem for me. I love CodeIgniter very much, and it's sped up my webdevelopment significantly. It being mildly US-centric though in the way it handles accented characters in URL's and Cart processing leaves a bit to be desired. The up side is that through its extensibility, you can make things work - allbeit with a bit of angry fist shaking. Having these workarounds present out of the box from within CodeIgniter would be nice. But that's another can of worms...

Standard