type != 'text/filepath') {
throw new Exception(t('You must use Shapefile Parser with File Fetcher.'));
}
$options = $source->getConfigFor($this);
$filepath = ($fetcherResult->value);
$shapefile_data = geo_process_shapefile($fetcherResult->value, $options['spatial_field_name']);
// Apply titles in lower case.
foreach ($shapefile_data['columns'] as $i => $title) {
$shapefile_data['columns'][$i] = strtolower($title); // Use lower case only.
}
$result_rows = array();
foreach ($shapefile_data['data'] as $i => $row) {
$result_row = array();
foreach ($row as $j => $col) {
$result_row[$shapefile_data['columns'][$j]] = $col;
}
$result_rows[] = $result_row;
}
// Return result.
return new FeedsParserResult(array('items' => $result_rows));
}
/**
* Override parent::getSourceElement to use only lower keys.
*/
public function getSourceElement($item, $element_key) {
$element_key = strtolower($element_key);
return isset($item[$element_key]) ? $item[$element_key] : '';
}
/**
* Define defaults.
*/
public function sourceDefaults() {
return array(
'spatial_field_name' => $this->config['spatial_field_name'],
'srid' => $this->config['srid'],
);
}
/**
* Source form.
*
* Show mapping configuration as a guidance for import form users.
*/
public function sourceForm($source_config) {
$form = array();
$form['#weight'] = -10;
$mappings = feeds_importer($this->id)->processor->config['mappings'];
$sources = $uniques = array();
foreach ($mappings as $mapping) {
$sources[] = $mapping['source'];
if ($mapping['unique']) {
$uniques[] = $mapping['source'];
}
}
$items = array(
t('Import zipped !shapefile with one or more of these columns: !columns.', array('!shapefile' => l(t('Shapefiles'), 'http://en.wikipedia.org/wiki/Shapefile'), '!columns' => implode(', ', $sources))),
format_plural(count($uniques), t('Column !column is mandatory and considered unique: only one item per !column value will be created.', array('!column' => implode(', ', $uniques))), t('Columns !columns are mandatory and values in these columns are considered unique: only one entry per value in one of these column will be created.', array('!columns' => implode(', ', $uniques)))),
);
$form['help']['#value'] = '
'. theme('item_list', $items) .'
';
$form['spatial_field_name'] = array(
'#type' => 'textfield',
'#title' => t('Spatial Data Column'),
'#default_value' => $source_config['spatial_field_name'],
'#size' => 24,
'#maxlength' => 24,
'#description' => t('The database column name that the spatial data should be stored in.')
);
$form['srid'] = array(
'#type' => 'textfield',
'#title' => t('SRID (Spatial projection)'),
'#default_value' => $source_config['srid'],
'#size' => 24,
'#maxlength' => 24,
'#description' => t('Integer represeting the SRID of the uploaded shapefile. If you are unsure, use \'4326\' (lat/lon).')
);
return $form;
}
/**
* Define default configuration.
*/
public function configDefaults() {
return array(
'spatial_field_name' => 'geom',
'srid' => '4326',
);
}
}
/**
* Process Shapefile
*
* This is where the action happens. Given a path, get all the data out of a
* zipped shapefile.
*/
function geo_process_shapefile($filepath, $spatial_field = 'geom') {
include_once(drupal_get_path('module', 'geo') .'/includes/shp2sql.inc');
if (!is_readable($filepath) || (!is_resource($zip = zip_open($filepath)))) {
drupal_set_message(t('zip file nonexistant or unreadable.'), 'error');
return;
}
// Catalog the contents of the zip file.
$files = array();
while ($res = zip_read($zip)) {
$ext = strtolower(substr(strrchr(zip_entry_name($res), '.'), 1));
$files[$ext] = $res;
}
// The zip file must minimally contain a shp, dbf and shx file.
if (!isset($files['shp']) || !isset($files['dbf']) || !isset($files['shx'])) {
drupal_set_message(t('This does not appear to be an archive that contains valid shp data.'), 'error');
return;
}
// See if we can get the projection information from the prj file.
if (isset($files['prj'])) {
// TODO Parse srid from prj file, for conversion if necessary.
}
if (isset($files['dbt'])) {
drupal_set_message(t('This database contains longtext/memo fields, which are unsupported. Proceeding to enter other data anyway.'), 'warning');
}
// Get headers and table definition from the dbf file.
$schema = array('description' => t('Imported shapefile'), 'fields' => array());
$headers = _dbf_headers($files['dbf'], $schema);
// Shape file headers are stored in the first 100 bytes of the shp/shx files.
$headers += _shp_headers(zip_entry_read($files['shp'], 100));
// Get column names
$columns = array_keys($headers['field_lengths']);
// Add 'spatial_field' to the list of columns
$columns[] = $spatial_field;
// Add spatial_field to schema
$schema['fields'][$spatial_field] = array (
'type' => 'blob',
'mysql_type' => 'geometry',
'pgsql_type' => 'geometry',
'gis type' => $headers['geo_type'],
'description' => 'Geomtry Field'
);
$data = array();
$row_count = 0;
while ($shp = _shp_get_record($files['shp'])) {
$values = array();
$dbf_data = zip_entry_read($files['dbf'], $headers['record_size']);
$dbf_data = substr($dbf_data, 1); // Remove "record deleted" flag.
foreach($headers['field_lengths'] as $name => $length) {
$value = substr($dbf_data, 0, $length);
$dbf_data = substr($dbf_data, $length);
// Use a predefined function to filter and process each value.
$process = $headers['field_filters'][$name];
$values[] = $value;
}
// Add the geometry text.
$values[] = $shp['data']['wkt'];
$data[] = $values;
$row_count++;
}
return array(
'schema' => $schema,
'headers' => $headers,
'columns' => $columns,
'shapecolumn' => $spatial_field,
'data' => $data,
'srid' => NULL,
);
}
?>