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, ); } ?>