views_geojson.module in Views GeoJSON 6
Same filename and directory in other branches
Provide a GeoJSON Views feed style.
File
views_geojson.moduleView source
<?php
/**
* @file
* Provide a GeoJSON Views feed style.
*/
/**
* Implements hook_views_api().
*/
function views_geojson_views_api() {
return array(
'api' => '2.0',
'path' => drupal_get_path('module', 'views_geojson') . '/views',
);
}
/**
* We almost duplicate the content_handler_field_multiple::render function
* to get the multiple rendered field values in an array
* @param $field
* @param $values
* @return unknown_type
*/
function _views_geojson_render_multiple_field($field, $values) {
$options = $field->options;
// If this is not a grouped field, use content_handler_field::render().
if (!$field->defer_query) {
return $field
->render($values);
}
// We're down to a single node here, so we can retrieve the actual field
// definition for the node type being considered.
$content_field = content_fields($field->content_field['field_name'], $values->{$field->aliases['type']});
$vid = $values->{$field->field_alias};
if (isset($field->field_values[$vid])) {
// Gather items, respecting the 'Display n values starting from m' settings.
$count_skipped = 0;
$items = array();
foreach ($field->field_values[$vid] as $item) {
if (empty($options['multiple']['multiple_from']) || $count_skipped >= $options['multiple']['multiple_from']) {
if (empty($options['multiple']['multiple_number']) || count($items) < $options['multiple']['multiple_number']) {
// Grab the nid - needed for render_link().
$nid = $item['_nid'];
unset($item['_nid']);
$items[] = $item;
}
else {
break;
}
}
$count_skipped++;
}
// Build a pseudo-node from the retrieved values.
$node = drupal_clone($values);
// content_format and formatters will need a 'type'.
$node->type = $values->{$field->aliases['type']};
$node->nid = $values->{$field->aliases['nid']};
$node->vid = $values->{$field->aliases['vid']};
// Some formatters need to behave differently depending on the build_mode
// (for instance: preview), so we provide one.
$node->build_mode = NODE_BUILD_NORMAL;
// Render items.
$formatter_name = $options['format'];
if ($items && ($formatter = _content_get_formatter($formatter_name, $content_field['type']))) {
$rendered = array();
if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) {
// Single-value formatter.
$n = 0;
foreach ($items as $item) {
$output = content_format($content_field, $item, $formatter_name, $node);
if (!empty($output)) {
$rendered[++$n] = $field
->render_link($output, (object) array(
'nid' => $nid,
));
}
}
}
else {
// Multiple values formatter.
$output = content_format($content_field, $items, $formatter_name, $values);
if (!empty($output)) {
$rendered[++$n] = $field
->render_link($output, (object) array(
'nid' => $nid,
));
}
}
if (count($rendered) > 1) {
// TODO: could we use generic field display ?
//return theme('content_view_multiple_field', $rendered, $content_field, $values);
return $rendered;
}
elseif ($rendered) {
return $rendered[1];
}
}
}
return '';
}
/**
* Takes each field from a row object and renders the field as determined by the field's theme.
*
* @param $view
* View the row belongs to
* @param $row
* Row object
* @return array
* Object containing all the raw and rendered fields
*/
function _views_geojson_render_fields($view, $row, $index) {
$excluded_fields = array();
$feature = array(
'type' => 'Feature',
);
$data_source = $view->style_plugin->options['data_source'];
$field_ids = array_keys($view->field);
// Pre-render fields to handle those rewritten with tokens
foreach ($view->field as $field_idx => $field) {
$field
->advanced_render($row);
}
switch ($data_source['value']) {
case 'latlon':
$options = array(
'latitude',
'longitude',
);
$latitude = NULL;
$longitude = NULL;
foreach ($view->field as $field_idx => $field) {
foreach ($options as $option) {
if ($data_source[$option] == $field_idx) {
${$option} = $field
->advanced_render($row);
$excluded_fields[] = $field_idx;
}
}
}
if (!empty($latitude) && !empty($longitude)) {
$feature['geometry'] = array(
'type' => 'Point',
'coordinates' => array(
floatval($longitude),
floatval($latitude),
),
);
}
break;
case 'geofield':
foreach ($view->field as $field_idx => $field) {
if ($data_source['geofield'] == $field_idx) {
$geofield = $view->style_plugin
->get_field_value($view->row_index, $field_idx);
$geofield = $geofield[0]['wkt'];
$view->row_index = $index;
$excluded_fields[] = $field_idx;
}
}
if (!empty($geofield)) {
geophp_load();
$json = geoPHP::load($geofield, 'wkt');
if (is_object($json)) {
$feature['geometry'] = json_decode($json
->out('json'));
}
}
break;
case 'wkt':
foreach ($view->field as $field_idx => $field) {
if ($data_source['wkt'] == $field_idx) {
$wkt = $field
->advanced_render($row);
$excluded_fields[] = $field_idx;
}
}
if (!empty($wkt)) {
geophp_load();
$json = geoPHP::load($wkt, 'wkt');
if (is_object($json)) {
$feature['geometry'] = json_decode($json
->out('json'));
}
}
break;
}
// Only add features with geometry data
if (empty($feature['geometry'])) {
return;
}
// Add the name and description attributes
// as chosen through interface
if ($data_source['name_field']) {
foreach ($view->field as $field_idx => $field) {
if ($data_source['name_field'] == $field_idx) {
$name_field = $field
->advanced_render($row);
$excluded_fields[] = $field_idx;
}
}
$feature['properties']['name'] = $name_field;
}
else {
$feature['properties']['name'] = '';
}
if ($data_source['description_field']) {
foreach ($view->field as $field_idx => $field) {
if ($data_source['description_field'] == $field_idx) {
$description_field = $field
->advanced_render($row);
$excluded_fields[] = $field_idx;
}
if ($data_source['description_field'] === '#node') {
$view_mode = $data_source['view_mode'] ? $data_source['view_mode'] : 'full';
$description_field = drupal_render(node_view(node_load($row->nid), $view_mode));
}
}
$feature['properties']['description'] = $description_field;
}
else {
$feature['properties']['description'] = '';
}
// Fill in attributes that are not:
// - Coordinate fields
// - Name/description (already processed)
// - Views "excluded" fields
foreach ($field_ids as $id) {
$field = $view->field[$id];
if (!in_array($id, $excluded_fields, TRUE) && !$field->options['exclude']) {
$value_rendered = $field
->advanced_render($row);
$feature['properties'][$id] = is_numeric($value_rendered) ? floatval($value_rendered) : $value_rendered;
}
}
return $feature;
}
/**
* Encodes GeoJSON in a pretty-printed fashion.
*/
function _views_geojson_encode_formatted($v, $depth = 0) {
$base_indent = ' ';
$eol = '<br />';
$indent = str_repeat($base_indent, $depth);
// This is based on the drupal_to_js() function.
switch (gettype($v)) {
case 'boolean':
// Lowercase is necessary!
return $v ? 'true' : 'false';
case 'integer':
case 'double':
return $v;
case 'resource':
case 'string':
$search = array(
'"',
chr(92),
chr(8),
chr(12),
chr(13) . chr(10),
chr(10),
chr(13),
chr(9),
);
$replace = array(
'\\"',
'\\',
'\\b',
'\\f',
'\\n',
'\\n',
'\\r',
'\\t',
);
$output = str_replace($search, $replace, $v);
/* *
$output = str_replace(array("\r", "\n", "<", ">", "&"),
array('\r', '\n', '\x3c', '\x3e', '\x26'),
addslashes($output));
/* */
return '"' . check_plain($output) . '"';
case 'array':
// Arrays in JSON can't be associative. If the array is empty or if it
// has sequential whole number keys starting with 0, it's not associative
// so we can go ahead and convert it as an array.
if (empty($v) || array_keys($v) === range(0, sizeof($v) - 1)) {
$output = array();
foreach ($v as $val) {
$output[] = $indent . $base_indent . _views_geojson_encode_formatted($val, $depth + 1);
}
return '[' . (!empty($output) ? $eol . implode(',' . $eol, $output) . $eol . $indent : '') . ']';
}
// Otherwise, fall through to convert the array as an object.
case 'object':
$output = array();
foreach ($v as $key => $val) {
$output[] = $indent . $base_indent . _views_geojson_encode_formatted(strval($key)) . ' : ' . _views_geojson_encode_formatted($val, $depth + 1);
}
return '{' . (!empty($output) ? $eol . implode(',' . $eol, $output) . $eol . $indent : '') . '}';
default:
return 'null';
}
}
Functions
Name | Description |
---|---|
views_geojson_views_api | Implements hook_views_api(). |
_views_geojson_encode_formatted | Encodes GeoJSON in a pretty-printed fashion. |
_views_geojson_render_fields | Takes each field from a row object and renders the field as determined by the field's theme. |
_views_geojson_render_multiple_field | We almost duplicate the content_handler_field_multiple::render function to get the multiple rendered field values in an array |