Geocoding addresses with the Geocodable behavior

Since the introduction of Google Maps and other location services, a broad set of possibilities are open to web applications, allowing geographical information to be used for building services.

This recipe shows how to use the Geocode plugin to add location information to our own Address model, allowing us to search address records by proximity.

Note

The Geocode plugin is another open source project I released. More information about it can be obtained at http://github.com/mariano/geocode.

Getting ready

To go through this recipe we need a sample table to work with. Create a table named addresses, using the following SQL statement:

CREATE TABLE `addresses`(
`id` INT UNSIGNED AUTO_INCREMENT NOT NULL,
`address_1` VARCHAR(255) NOT NULL,
`city` VARCHAR(255) default NULL,
`state` VARCHAR(255) NOT NULL,
`zip` VARCHAR(10) default NULL,
`latitude` FLOAT(10,7) NOT NULL,
`longitude` FLOAT(10,7) NOT NULL,
PRIMARY KEY(`id`)
);

We proceed now to create the required model. Create the model Address in a file named address.php and place it in your app/models folder with the following contents (we are only specifying a few states for readability):

<?php
class Address extends AppModel {
public $validate = array(
'address_1' => array('rule' => 'notEmpty'),
'state' => array('rule' => 'notEmpty')
);
public static $states = array(
'CA' => 'California',
'FL' => 'Florida',
'NY' => 'New York'
);
}
?>

Create its appropriate controller AddressesController in a file named addresses_controller.php and place it in your app/controllers folder. With the following contents:

<?php
class AddressesController extends AppController {
public function add() {
if (!empty($this->data)) {
$this->Address->create();
if ($this->Address->save($this->data)) {
$this->Session->setFlash('Address created'),
$this->redirect('/'),
} else {
$this->Session->setFlash('Please correct the errors'),
}
}
$states = $this->Address->states;
$this->set(compact('states'));
}
}
?>

Create a folder named addresses in your app/views folder, then create the view to hold the form in a file named add.ctp and place it in your app/views/addresses folder, with the following contents:

<?php
echo $this->Form->create();
echo $this->Form->inputs(array(
'address_1' => array('label' => 'Address'),
'city',
'state' => array('options'=>$states),
'zip'
));
echo $this->Form->end('Create'),
?>

We need to download the Geocode plugin for CakePHP. Go to http://github.com/mariano/geocode/downloads and download the latest release. Uncompress the downloaded file into your app/plugins folder. You should now have a directory named geocode inside app/plugins.

Finally, we need to sign up for a Google Maps API key. To do so, go to http://code.google.com/apis/maps/signup.html and follow the instructions given.

Note

The Geocode plugin also supports Yahoo maps. If you wish to use Yahoo Maps instead, follow the instructions shown on the plugin homepage.

How to do it...

  1. Edit your app/config/bootstrap.php file and place the following statement right before the closing PHP statement, replacing the string APIKEY with your own Google Maps API key:
    Configure::write('Geocode.key', 'APIKEY'),
    
  2. We will now make our Address model extend the skeleton model provided by the plugin. Edit your app/models/address.php file and make the following changes:
    <?php
    App::import('Model', 'Geocode.GeoAddress'),
    class Address extends GeoAddress {
    public $validate = array(
    'address_1' => array('rule' => 'notEmpty'),
    'state' => array('rule' => 'notEmpty')
    );
    public static $states = array(
    'CA' => 'California',
    'FL' => 'Florida',
    'NY' => 'New York'
    );
    }
    ?>
    
  3. By extending GeoAddress, the Geocodable behavior is automatically attached to our model. We can now use the form at http://localhost/addresses/add to add new addresses. After adding quite a few, we are ready to implement a paginated listing with support to finding addresses that are near a certain location.
  4. To simplify this operation, we will force the point of origin in our controller action, instead of letting the user specify the address. With this in mind, add the following action to the AddressesController class:
    public function index() {
    $address = '1211 La Brad Lane, Tampa, FL';
    $this->paginate = array(
    'near',
    'address' => $address
    );
    $addresses = $this->paginate();
    $this->set(compact('address', 'addresses'));
    }
    
  5. Now create the view app/views/addresses/index.ctp, with the following contents:
    <h1>Addresses near <strong><?php echo $address; ?></strong></h1>
    <div class="paging">
    <?php echo $this->Paginator->prev(); ?>
    &nbsp;
    <?php echo $this->Paginator->numbers(); ?>
    &nbsp;
    <?php echo $this->Paginator->next(); ?>
    </div>
    <br />
    <ul>
    <?php foreach($addresses as $currentAddress) { ?>
    <li>
    <?php echo $currentAddress['Address']['address_1']; ?>
    at
    <strong><?php echo number_format($currentAddress['Address']['distance'], 2) . ' km.'; ?></strong>
    </li>
    <?php } ?>
    </ul>
    

If you inserted sample addresses that are near the specified address, the output could be similar to that shown in the following screenshot:

How to do it...

How it works...

We started by downloading the plugin and configuring it by setting our own Google Maps API key in the bootstrap.php configuration file. We then made our Address model inherit from the GeoAddress model provided by the plugin, which makes our model use the Geocodable behavior, and implements the near custom find type.

Since our Address model is now attached to the Geocodable behavior, every time we create new address records the plugin will use the Google Maps API to save the appropriate location in the latitude and longitude fields.

Using the near custom find type, we can easily find addresses that are near a certain address, and we can also see what distance separates each of those addresses from the point of origin.

There's more...

The Geocode plugin is quite flexible, and even includes a helper to show addresses in a visual map. To find out all it has to offer, go to its website at http://github.com/mariano/geocode.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.253.198