Insertar un formulario de filtro del módulo view en un node

  • 9 Nov 2011
  • Drupal

Esto nace de la necesidad de relacionar dos valores de un mismo tipo de contenido. Imaginando un tipo de contenido en el que se cargan: Fecha, Modeda, Cotización a USD.

En este tipo de contenido se cargan cotizaciones de varias monedas del mundo.

Se quiso hacer una tabla con las cotizaciones históricas del Peso Argentino, por ejemplo, y fue fácil. Una simple vista. Después se quiso colocar un filtro en el que se pueda elegir la moneda. También fácil. Se configuró un "exposed filter".

Y después alguien pidió que se puedan saber las cotizaciones del Peso Argentino, pero por ejemplo a Euros en vez de dólares. Y entonces se cayó un edificio en Buenos Aires.

Con el módulo views se podrían traer las dos monedas seleccionadas. Pero.. no encontré la manera de hacer la conversión entre las dos. Y menos ocultar la fila que sobra. Con jQuery.. pero sería un delirio. No se suelen descartar los delirios. Pero esta vez sí.

Entonces.. teniendo el query que hace la vista se vio que bastaba una pequeña modificación para traer los dos valores en un campo. Usando GROUP_CONCAT. Una gloria.

Bueno.. Pero como ponemos un filtro. No solo uno. Él filtro. El mismo que usamos en la vista? Y Google me dijo:

$view = views_get_view('rates');
$view->set_display('default');
$view->init_handlers();
$form_state = array(
  'view' => $view,
  'display' => $view->display_handler->display,
  'method' => 'get',
  'rerender' => TRUE,
  'no_redirect' => TRUE,
);
$output = drupal_build_form('views_exposed_form', $form_state);

Solo un problema. Cuando hago click en el botón submiteador, va a la url de la vista. Entonces.. cambiamos el formulario con un gancho.. o con un hook. El siguiente:

function term_owner_form_alter(&$form, $form_state, $form_id) {

  switch ($form_id) {
    case 'record_node_form':
      $form['#validate'][] = 'term_owner_currency_good';
      break;
    case 'views_exposed_form': // y no quiero que vayas a la url de la vista
      $form['#action'] = '?';
      break;
  }        
}

Al final, queda seguir con el node. Que ya tiene el código de arriba. Hay que traer las variables del formulario. Fácil:

$to = $_REQUEST['to'];
$from = $_REQUEST['from'];
$date_from = $_REQUEST['date_from']['value']['date']."T00:00:00";
$date_to = $_REQUEST['date_to']['value']['date']."T00:00:00";

Después, ponerlas en el query "dinámico". Notesé la presencia del glorioso GROUP_CONCAT

$query = "
  SELECT 
    GROUP_CONCAT(node_data_field_rate.field_rate_value ORDER BY node_data_field_currency.field_currency_value SEPARATOR '/') AS rate,
    node.nid AS nid,
    node_data_field_date.field_date_value AS date,
    node.type AS node_type,
    node.vid AS node_vid,
    node_data_field_currency.field_currency_value,
    node.uid AS node_uid
  FROM 
    node node 
  LEFT JOIN 
    content_field_date node_data_field_date ON node.vid = node_data_field_date.vid
  LEFT JOIN 
    content_field_currency node_data_field_currency ON node.vid = node_data_field_currency.vid
  LEFT JOIN 
    content_type_rates node_data_field_rate ON node.vid = node_data_field_rate.vid
  LEFT JOIN 
    node_revisions node_revisions ON node.vid = node_revisions.vid
  WHERE 
    node.type in ('rates')
    AND node_data_field_currency.field_currency_value IN ({$from},{$to}) 
    AND (node_data_field_date.field_date_value > '{$date_from}' AND node_data_field_date.field_date_value < '{$date_to}')
  GROUP BY 
    node_data_field_date.field_date_value
";

Después de eso, un poco de tabla, paginación y query también:

// cuantos resultados hay?
$count_query = "SELECT COUNT(*) FROM (" . $query . ") AS count_query";

// encabezado de la tabla
$header = array(
  array('data' => 'Date', 'field' => 'date', 'sort' => 'desc'), 
  array('data' => 'Quote', 'field' => 'rate')
);

// cuando se "sortea" la tabla, se altera el query
$tablesort = tablesort_sql($header, " ");
$result = pager_query($query . $tablesort, 10, 0, $count_query);

// se genera el array, calculando el tipo de cambio
while ($row = db_fetch_object($result)) {
  $rates = explode("/", $row->rate);
  $quote = "ND";
  if (is_array($rates) && $rates[1] > 0) {
    $quote = floatval($rates[0])/floatval($rates[1]); 
  }
  $data[] = array($row->date, $quote);
}

// se hachetemelea la tabla
$output .= theme('table', $header, $data);

// y también el paginador
$output .= theme('pager', NULL, 10, 0);

// y finalmente, el fin
return $output;