October 24th, 2008 // 11:28 pm

Getting started with the Google Maps API and CodeIgniter

This week during my week of work experience I was given the task of creating an application for mapping crimes in Dublin. So here I am sharing with you what I learnt. We’ll create a simple application that loads points from a database and shows them on a map. Using Javascript, PHP, MySQL and CodeIgniter, I’ll assume you have a webserver running and understand PHP and MySQL. Note: I think I may have mixed up longitude and latitude throughout the tutorial. It’ll still work, they’re just labeled incorrectly

Lets get setup

So we’ll start by downloading CodeIgniter (CI) from codeigniter.com. Done? ok. Copy it to a directory on your web server and visit your new CI install in your browser. Incase you don’t know CodeIgniter is an open-source PHP MVC framework which gives us a nice application structure to work with.

Fantastic! We also need to get a Google Maps API key from Google Code. We’ll need this later on, so keep it safe.

Time to start real work

Open up the application directory (in the system directory) and lets get started. We’ll mostly be working in the application directory, all of our code, goes in here. We’ll start by renaming controllers/welcome.php to main.php and opening up the routes.php (in the config directory) file.

Routes.php defines the urls for our application. Find the following line

$route['default_controller'] = "welcome";

And change it to:

$route['default_controller'] = "main";

We need to do this since we renamed welcome.php to main.php. This process isn’t entirely necessary but I like to do it.

You also need to open up config.php (in config) and change the base_url setting to match the base url of your site.

Now lets open up main.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
 
class Welcome extends Controller {
 
	function Welcome()
	{
		parent::Controller();
	}
 
	function index()
	{
		$this->load->view('welcome_message');
	}
}
 
/* End of file welcome.php */
/* Location: ./system/application/controllers/welcome.php */

Note: We need to replace the instances of Welcome on the lines 3 and 5 with Main because we renamed our controller.

Controllers are the link between the view, where we show the user the data and the model where we get the data from (a rough explanation of MVC, I know.). So lets start by doing a nice little hello world. Change the $this->load->view line, to load ‘main_view’ instead of ‘welcome_message’.

Open up the view directory and delete welcomemessage, we won’t be needing it anymore. And create ‘mainview.php’, note how we didn’t have to specify the .php suffix while loading the view, put the following into your view.

<p>Hello world?</p>

If you refresh in your browser right now you should see your lovely hello world message, cool huh? Well maybe you’re thinking that was a lot of effort for just that. It’ll help in the long run, I promise!

Setup the Database

Woops! I almost forget, we need to setup the database. Open up phpMyAdmin (or some mysql interface) and create a database called ‘parties’ and run the following query:

CREATE TABLE IF NOT EXISTS `locations` (
  `ID` int(10) UNSIGNED NOT NULL,
  `title` varchar(64) character SET utf8 collate utf8_unicode_ci NOT NULL,
  `summary` text NOT NULL,
  `longitude` double NOT NULL,
  `latitude` double NOT NULL,
  PRIMARY KEY  (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

That should create all the fields we’ll need for our application. All you need to do now is fill out the relevant info in config/database.php.

Work with a beautiful model

Time to create a model. A model is how we interact with the database in CodeIgniter or any MVC application. Create a new file in the models directory called ‘locations.php’. I find it best to name models after the tables which they represent. Copy the following code into your model:

<?php
 
class Locations extends Model {
 
	/*
	*	Get the locations we want to put on our map
	*/
	function get_locations() {
		// Load the database class
		$this->load->database();
 
		// Get all the entries in the parties table.
		$query = $this->db->get('locations');
 
		// Are there any results from our query?
		if($query->num_rows() > 0)
		{
			// Set a counter to 0
			$n = 0;
 
			// Create our array
			$data = array();
 
			// Loop through the results filling our array with the locations
			foreach($query->result_array() as $row)
			{
				$data[$n]['title'] = $row['title'];
				$data[$n]['summary'] = $row['summary'];
				$data[$n]['longitude'] = $row['longitude'];
				$data[$n]['latitude'] = $row['latitude'];
				$n++;
			}
 
			// Return the array
			return $data;
		}
 
		// Returns false if we didn't get any results from our query
		return false;
	}
 
	/*
	*	Create a location for our map
	*/
	function create_location($data)
	{
		// Load the database class
		$this->load->database();
 
		// Insert the data into the table
		$this->db->insert('locations', $data);
	}
 
}

Lets walk through how each method works. get_locations will provide our map with all the data we need to generate a map. We load the database library, get all the entries from our locations table. We then check if we got any results, to avoid errors and fill an array with our data. Simple enough.

create_location couldn’t be simpler, it just inserts an array which is passed to it into the database. Which of course in real life would be validated and cleaned before being inserted into the database, but this is just a tutorial, ok?

Back to the controller!

That’s our model done. Now we need to flesh out our poor controller.

<?php
 
class Main extends Controller {
 
	function Main()
	{
		parent::Controller();
	}
 
	function index()
	{
		// Load the locations model
		$this->load->model('locations');
 
		// Populate an array with all the locations we want to put on our map.
		$data['locations'] = $this->locations->get_locations();
 
		// Load our view
		$this->load->view('main_view', $data);
	}
 
	function create()
	{
		// Load the url helper, for the view and the redirect below
		$this->load->helper('url');
 
		if(!isset($_POST['submit']))
		{
			$this->load->view('create_view');
			return;
		}
 
		// Load the locations model
		$this->load->model('locations');
 
		// Fill the array with what we want to put in the database
		$data = array(
				'title' => $this->input->post('title'),
				'summary' => $this->input->post('summary')
			);
 
		/* Get the longitude and latitude out of the stupid (x, y) string. */
		// Strip the brackets
		$location = substr(substr($_POST['location'], 0, -1), 1, -1);
 
		// Split it up into two numbers
		$location = explode(', ', $location);
 
		// Add our longitude and latitude to our array
		$data['longitude'] = $location[0];
		$data['latitude'] = $location[1];
 
		// And put it in the database
		$this->locations->create_location($data);
 
		// Redirect the user to the homepage
		redirect();
	}
}

This is also pretty simple. The index method is the first method called when this controller is called. So we want this to load our ‘main_view’. We fill an array with the data from our database and pass this array to the view through the second parameter.

Our create method will let us create a location to put on the map. It first checks if the form has been submitted and if not loads a view with the form on it (we’ll make that in a second). If the form has been submitted we fill an array with the form data, do some funky stuff to get the longitude and latitude. Finally we put it in the database and redirect the user to the homepage.

Create won’t work yet!

Well none of it works yet, but for create to work we need to tweak our routes.php just add the following line:

 
$route['create'] = 'main/create';

This tells CodeIgniter that when someone visits /create they want to load main/create. Also we need to create the view so go ahead and create create_view.php.

Time to make our create_view.

<html>
	<head>
		<script type="text/javascript" src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=YOURAPIKEY"></script>
 
		<script type="text/javascript">
			function initialize()
			{
				/*** Create our Map ***/
				var map = new GMap2(document.getElementById("map_canvas"));
				var mapControl = new GMapTypeControl();
				var center = new GLatLng(53.332923,-6.239548); // Center the map on dublin.
 
				map.setCenter(center, 11);
				map.addControl(mapControl);
				map.addControl(new GLargeMapControl());
				map.enableScrollWheelZoom();
 
				main(map, center);
			}
 
			function main(map, center)
			{
				// Create our Marker
				var marker = new GMarker(center, {draggable: true});
 
				// Set the lattiude longitude hidden field to the center of the map, incase they don't move it.
				document.getElementById('latlng').value = center;
/*
				/*** Detect when the marker is moved and update the hidden field ***/
				GEvent.addListener(marker, "dragstart", function()
				{
				  map.closeInfoWindow();
				});
 
				GEvent.addListener(marker, "dragend", function()
				{
					document.getElementById('latlng').value = marker.getLatLng(); // Update the hidden form field.
				});
 
				map.addOverlay(marker);
			}
		</script>
	</head>
 
	<body onload="initialize()" onunload="GUnload()">
		<h1>Tell us about a party!</h1>
 
		<form method="post" action="<?php echo site_url('create');?>">
 
			<strong>Title: </strong><input type="text" name="title" />
			<strong>Summary: </strong><input type="text" name="summary" />
 
			<br/><br/>
 
			<div id="map_canvas" style="width: 500px; height: 300px;"></div>
			<input type="hidden" name="location" id="latlng" value=""/>
 
			<br/><br/>
 
			<input type="submit" name="submit" value="Submit"/>
		</form>
	</body>
</html>

Note: in this example and the next you need to fill in YOURAPIKEY with the api key you got earlier from google.

Looks confusing? It’s really not. When the page is loaded the onload=”initialize()” causes the initialize function to be called (which is javscript), which creates a new map on the #map_canvas div and then sets the center, etc.

The initialize function then calls the main function which puts a marker in the center of our map and adds listeners which detect when it’s been moved and if it has updates the hidden field with the new latitude and longitude.

If you know browse to example.com/index.php/create you will see the beautiful (well it’s rather ugly… but… yeah :) ) form we just created. If you fill in the details and click create it will insert it into the database and redirect you to our front page.

Hello World

Hi! But that’s not what we want, we want our map! Finally we just need to update our main_view.

<html>
	<head>
		<script type="text/javascript" src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=YOURAPIKEY"></script>
 
		<script type="text/javascript">
			function initialize()
			{
				/*** Create our Map ***/
				var map = new GMap2(document.getElementById("map_canvas"));
				var mapControl = new GMapTypeControl();
				var center = new GLatLng(53.332923,-6.239548); // Center the map on dublin.
 
				map.setCenter(center, 11);
				map.addControl(mapControl);
				map.addControl(new GLargeMapControl());
				map.enableScrollWheelZoom();
 
				main(map, center);
			}
 
			function showPoint(location, i)
			{
				var summary = '<h1 style="margin-bottom:0">'+location['title']+'</h1>' + '<p style="width: 300px;">'+location['summary']+'</p>';
 
 
		  		marker = new GMarker(location['location']);
				this.map.addOverlay(marker);
				marker.bindInfoWindowHtml(summary);
			}
 
			function main(map, center)
			{
				this.map = map;
				this.center = center;
 
				this.locations = [];
 
				<?php
				if(!empty($locations))
				{
					$n = 0;
					foreach($locations as $location)
					{
						echo "this.locations[$n] = [];\n";
						echo "this.locations[$n]['title'] = '".$location['title']."';\n";
 
						echo "this.locations[$n]['location'] = new GLatLng(".$location['longitude'].", ".$location['latitude'].");\n";
 
						echo "this.locations[$n]['summary'] = '".$location['summary']."';\n";
						$n++;
					}
				}
				?>
 
				for (var i = 0; i < locations.length; ++i)
				{
					showPoint(locations[i], i);
				}
			}
		</script>
	</head>
 
	<body onload="initialize()" onunload="GUnload()">
		<h1>Parties!</h1>
		<div id="map_canvas" style="width: 500px; height: 300px;"></div>
	</body>
</html>

Reload, et voila.

The initialize function is the same here as before. However this time in the main function we populate a javascript array from our php array, which we then loop through and pass to our showPoint function which shows the point on the map along with our title and description, which will show up when the marker is clicked.

Wrap Up!

Well that turned out a lot longer than I expected but hopefully it covers all you need to know about getting started with codeigniter + google maps api. Of course if I were creating a real site there’re several things I’d do differently, which for length reasons weren’t discussed here. I’ve listed some here:

  • I would make it less ugly
  • I would split up the top and the bottom of both the views into a header and footer view, and then load them so they surround our main content on every page. This means if you want to change the layout of your site you don’t have to update every view
  • I would put some of the javascript into it’s own file, for the same reasons.
  • I would put the api key into a config file and load it into our view, again if we need to change our api key, we don’t have to change every file
  • I would autoload commonly used models, libraries and helpers

You can download the code here.

Enjoy, Ben.

P.S. If you liked this tutorial please leave a comment!