Skip to content

Instantly share code, notes, and snippets.

@fabsor
Created April 16, 2012 17:27
Show Gist options
  • Save fabsor/2400105 to your computer and use it in GitHub Desktop.
Save fabsor/2400105 to your computer and use it in GitHub Desktop.
From 000cb8fd3f2ef56b8b4baf346801c081f483648a Mon Sep 17 00:00:00 2001
From: Fabian Sorqvist <fabian.sorqvist@gmail.com>
Date: Mon, 16 Apr 2012 19:26:44 +0200
Subject: [PATCH] Views integration
---
entity_translation.info | 6 +
entity_translation.module | 10 +
views/entity_translation.views.inc | 227 ++++++++++++++++++++
views/entity_translation_handler_field_label.inc | 72 ++++++
...ty_translation_handler_field_translate_link.inc | 96 ++++++++
...tity_translation_handler_filter_entity_type.inc | 30 +++
.../entity_translation_handler_filter_language.inc | 27 +++
...anslation_handler_filter_translation_exists.inc | 132 ++++++++++++
views/entity_translation_handler_relationship.inc | 32 +++
9 files changed, 632 insertions(+), 0 deletions(-)
create mode 100644 views/entity_translation.views.inc
create mode 100644 views/entity_translation_handler_field_label.inc
create mode 100644 views/entity_translation_handler_field_translate_link.inc
create mode 100644 views/entity_translation_handler_filter_entity_type.inc
create mode 100644 views/entity_translation_handler_filter_language.inc
create mode 100644 views/entity_translation_handler_filter_translation_exists.inc
create mode 100644 views/entity_translation_handler_relationship.inc
diff --git a/entity_translation.info b/entity_translation.info
index 8fca343..a7dbc74 100644
--- a/entity_translation.info
+++ b/entity_translation.info
@@ -7,3 +7,9 @@ dependencies[] = locale
files[] = includes/translation.handler.inc
files[] = includes/translation.handler.node.inc
files[] = tests/entity_translation.test
+files[] = views/entity_translation_handler_relationship.inc
+files[] = views/entity_translation_handler_field_translate_link.inc
+files[] = views/entity_translation_handler_field_label.inc
+files[] = views/entity_translation_handler_filter_entity_type.inc
+files[] = views/entity_translation_handler_filter_language.inc
+files[] = views/entity_translation_handler_filter_translation_exists.inc
diff --git a/entity_translation.module b/entity_translation.module
index 467c110..e4087be 100644
--- a/entity_translation.module
+++ b/entity_translation.module
@@ -114,6 +114,16 @@ function entity_translation_entity_info_alter(&$entity_info) {
}
/**
+ * Implements hook_views_api().
+ */
+function entity_translation_views_api() {
+ return array(
+ 'api' => 3,
+ 'path' => drupal_get_path('module', 'entity_translation') . '/views',
+ );
+}
+
+/**
* Helper function to determine if the given entity type is translatable.
*/
function entity_translation_enabled($entity_type, $skip_handler = FALSE) {
diff --git a/views/entity_translation.views.inc b/views/entity_translation.views.inc
new file mode 100644
index 0000000..8a59f2f
--- /dev/null
+++ b/views/entity_translation.views.inc
@@ -0,0 +1,227 @@
+<?php
+/**
+ * @file
+ *
+ * Provide views data and handlers for entity_translation.
+ */
+
+/**
+ * Implements hook_views_data().
+ */
+function entity_translation_views_data() {
+ $data = array();
+ $data['entity_translation']['table']['group'] = t('Entity translation');
+ // Advertise this table as a possible base table.
+ $data['entity_translation']['table']['base'] = array(
+ 'field' => 'entity_id',
+ 'title' => t('Entity translation'),
+ 'help' => t('Information about a translation of an entity.'),
+ );
+ $data['entity_translation']['entity_id'] = array(
+ 'title' => t('Entity id'),
+ 'help' => t('The entity id.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_numeric',
+ 'click sortable' => TRUE,
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_numeric',
+ 'numeric' => TRUE,
+ 'validate type' => 'entity_id',
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_numeric',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+ $data['entity_translation']['entity_type'] = array(
+ 'title' => t('Entity type'),
+ 'help' => t('The entity type.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field',
+ 'click sortable' => TRUE,
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_string',
+ 'numeric' => FALSE,
+ 'validate type' => 'entity_type',
+ ),
+ 'filter' => array(
+ 'handler' => 'entity_translation_handler_filter_entity_type',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+ $data['entity_translation']['language'] = array(
+ 'title' => t('Language'),
+ 'help' => t('The language of this translation.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_locale_language',
+ 'click sortable' => TRUE,
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_locale_language',
+ 'numeric' => FALSE,
+ 'validate type' => 'language',
+ ),
+ 'filter' => array(
+ 'handler' => 'entity_translation_handler_filter_language',
+ 'allow empty' => TRUE,
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+ $data['entity_translation']['source'] = array(
+ 'title' => t('Source'),
+ 'help' => t('The source language.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_locale_language',
+ 'click sortable' => TRUE,
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_locale_language',
+ 'name field' => 'title',
+ 'numeric' => FALSE,
+ 'validate type' => 'string',
+ ),
+ 'filter' => array(
+ 'handler' => 'entity_translation_handler_filter_language',
+ 'allow empty' => TRUE,
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+ $data['entity_translation']['status'] = array(
+ 'title' => t('Translation status'),
+ 'help' => t('The status of this translation.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_boolean',
+ 'click sortable' => TRUE,
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_numeric',
+ 'numeric' => TRUE,
+ 'validate type' => 'boolean',
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_boolean_operator',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+ $data['entity_translation']['translate'] = array(
+ 'title' => t('Needs update'),
+ 'help' => t('Indicates if the translation needs to be updated.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_boolean',
+ 'click sortable' => TRUE,
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_numeric',
+ 'name field' => 'title',
+ 'numeric' => TRUE,
+ 'validate type' => 'boolean',
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_boolean_operator',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+ $data['entity_translation']['created'] = array(
+ 'title' => t('Created'),
+ 'help' => t('Created date.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_date',
+ 'click sortable' => TRUE,
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_date',
+ 'numeric' => FALSE,
+ 'validate type' => 'date',
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_date',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort_date',
+ ),
+ );
+ $data['entity_translation']['changed'] = array(
+ 'title' => t('Changed'),
+ 'help' => t('Changed date.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_date',
+ 'click sortable' => TRUE,
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_date',
+ 'numeric' => FALSE,
+ 'validate type' => 'date',
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_date',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort_date',
+ ),
+ );
+ $data['entity_translation']['translate_link'] = array(
+ 'title' => t('Translate link'),
+ 'help' => t('Link to translation overview page.'),
+ 'field' => array(
+ 'handler' => 'entity_translation_handler_field_translate_link',
+ ),
+ );
+ $data['entity_translation']['translation_exists'] = array(
+ 'title' => t('Translation exists'),
+ 'help' => t('Link to translation overview page.'),
+ 'filter' => array(
+ 'handler' => 'entity_translation_handler_filter_translation_exists',
+ ),
+ );
+ $data['entity_translation']['label'] = array(
+ 'title' => t('Label'),
+ 'help' => t('The label of the entity.'),
+ 'field' => array(
+ 'handler' => 'entity_translation_handler_field_label',
+ ),
+ );
+ return $data;
+}
+
+/**
+ * Implements hook_views_data_alter().
+ *
+ * Add entity translation information to the various entity tables.
+ */
+function entity_translation_views_data_alter(&$data) {
+ foreach (entity_get_info() as $type => $info) {
+ if ($info['fieldable'] && isset($data[$info['base table']])) {
+ $table = &$data[$info['base table']];
+ $table['entity_translations'] = array(
+ 'title' => t('Entity translation: translations'),
+ 'help' => t('Translation information.'),
+ 'relationship' => array(
+ 'label' => t('Translations'),
+ 'base' => 'entity_translation',
+ 'base field' => 'entity_id',
+ 'relationship field' => $info['entity keys']['id'],
+ 'handler' => 'entity_translation_handler_relationship',
+ // We add our information here in the definition,
+ // so we can copy it later.
+ 'left_table' => $info['base table'],
+ 'left_field' => $info['entity keys']['id'],
+ 'entity type' => $type,
+ ),
+ );
+ }
+ }
+}
diff --git a/views/entity_translation_handler_field_label.inc b/views/entity_translation_handler_field_label.inc
new file mode 100644
index 0000000..82a08bc
--- /dev/null
+++ b/views/entity_translation_handler_field_label.inc
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @file
+ * This file contains a label field handler for entity translation.
+ */
+
+/**
+ * This handler shows the entity label for entities in the entity_translation table.
+ */
+class entity_translation_handler_field_label extends views_handler_field {
+ function construct() {
+ parent::construct();
+ $this->additional_fields['entity_id'] = 'entity_id';
+ $this->additional_fields['entity_type'] = 'entity_type';
+ }
+
+ function query() {
+ $this->ensure_my_table();
+ $this->add_additional_fields();
+ }
+ /**
+ * Add a 'link to entity' option definition.
+ * @see views_handler_field::option:definition()
+ */
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['link_to_entity'] = array('default' => '', 'translatable' => FALSE);
+ return $options;
+ }
+
+ /**
+ * Add a 'link to entity' option.
+ * @see views_handler_field::options_form()
+ */
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $form['link_to_entity'] = array(
+ '#title' => t('Link this field to it\'s entity'),
+ '#type' => 'checkbox',
+ '#default_value' => $this->options['link_to_entity']
+ );
+ }
+
+ /**
+ * Load all entities, so that we can get the label.
+ */
+ function post_execute(&$values) {
+ $ids = array();
+ $ids_by_type = array();
+ foreach ($values as $row) {
+ $ids_by_type[$this->get_value($row, 'entity_type')][] = $this->get_value($row, 'entity_id');
+ }
+ foreach ($ids_by_type as $type => $ids) {
+ $this->entities[$type] = entity_load($type, $ids);
+ }
+ }
+
+ function render(&$values) {
+ $entity_type = $this->get_value($values, 'entity_type');
+ $entity_id = $this->get_value($values, 'entity_id');
+ $entity = $this->entities[$entity_type][$entity_id];
+ // We could also use entity_label(), but since this we might want to let
+ // the handler decide what's best to show.
+ $handler = entity_translation_get_handler($entity_type, $entity);
+ $label = $handler->getLabel();
+ if ($this->options['link_to_entity']) {
+ $this->options['alter']['make_link'] = TRUE;
+ $this->options['alter']['path'] = $handler->getViewPath();
+ }
+ return $label;
+ }
+}
diff --git a/views/entity_translation_handler_field_translate_link.inc b/views/entity_translation_handler_field_translate_link.inc
new file mode 100644
index 0000000..52985f9
--- /dev/null
+++ b/views/entity_translation_handler_field_translate_link.inc
@@ -0,0 +1,96 @@
+<?php
+/**
+ * @file
+ * Translate link plugin.
+ */
+
+/**
+ * This handler adds translate link for all translatable entities.
+ */
+class entity_translation_handler_field_translate_link extends views_handler_field {
+
+ function construct() {
+ parent::construct();
+ $this->additional_fields['entity_id'] = 'entity_id';
+ $this->additional_fields['entity_type'] = 'entity_type';
+ $this->additional_fields['language'] = 'language';
+ }
+
+ /**
+ * Add required additional fields.
+ */
+ function query() {
+ $this->ensure_my_table();
+ $this->add_additional_fields();
+ }
+
+ /**
+ * Add the text option.
+ * @see views_handler_field::option_definition()
+ */
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['text'] = array('default' => '', 'translatable' => TRUE);
+ return $options;
+ }
+ /**
+ * Add the option to set the title of the translate link.
+ * @see views_handler_field::options_form()
+ */
+ function options_form(&$form, &$form_state) {
+ $form['text'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Text to display'),
+ '#default_value' => $this->options['text'],
+ );
+ parent::options_form($form, $form_state);
+
+ // The path is set by render_link function so don't allow setting it.
+ $form['alter']['path'] = array('#access' => FALSE);
+ $form['alter']['external'] = array('#access' => FALSE);
+ }
+
+ /**
+ * Load all entities based on the data we have.
+ */
+ function post_execute(&$values) {
+ $ids = array();
+ $ids_by_type = array();
+ foreach ($values as $row) {
+ $ids_by_type[$this->get_value($row, 'entity_type')][] = $this->get_value($row, 'entity_id');
+ }
+ foreach ($ids_by_type as $type => $ids) {
+ $this->entities[$type] = entity_load($type, $ids);
+ }
+ }
+
+ /**
+ * @see views_handler_field::render()
+ */
+ function render($values) {
+ $type = $this->get_value($values, 'entity_type');
+ $entity_id = $this->get_value($values, 'entity_id');
+ $language = $this->get_value($values, 'language');
+ $entity = $this->entities[$type][$entity_id];
+ return $this->render_link($type, $entity_id, $language);
+ }
+
+ /**
+ * Render the link to the translation overview page of the entity.
+ */
+ function render_link($entity_type, $entity_id, $language) {
+ if (!entity_translation_enabled($entity_type) || !entity_translation_tab_access($entity_type) || $language == 'und') {
+ return;
+ }
+ // We use the entity info here to avoid having to call entity_load()
+ // for all entities.
+ $info = entity_get_info($entity_type);
+ $path = $info['translation']['entity_translation']['base path'];
+ $path = str_replace($info['translation']['entity_translation']['path wildcard'], $entity_id, $path);
+ $this->options['alter']['make_link'] = TRUE;
+ $this->options['alter']['path'] = $path . '/translate';
+ $this->options['alter']['query'] = drupal_get_destination();
+ $text = !empty($this->options['text']) ? $this->options['text'] : t('translate');
+ return $text;
+ }
+}
diff --git a/views/entity_translation_handler_filter_entity_type.inc b/views/entity_translation_handler_filter_entity_type.inc
new file mode 100644
index 0000000..5c2d8ef
--- /dev/null
+++ b/views/entity_translation_handler_filter_entity_type.inc
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @file
+ * Contains an entity type filter handler.
+ */
+
+/**
+ * handler shows all available entity types
+ * that are enabled for entity translation as options.
+ */
+class entity_translation_handler_filter_entity_type extends views_handler_filter_in_operator {
+
+ /**
+ * Show all entity types that are enabled for entity translation as options.
+ */
+ function get_value_options() {
+ if (!isset($this->value_options)) {
+ $this->value_title = t('Entity type');
+ $allowed_types_options = variable_get('entity_translation_entity_types');
+ $allowed_types = array();
+ $entity_info = entity_get_info();
+ foreach ($allowed_types_options as $key => $allowed) {
+ if ($allowed) {
+ $allowed_types[$key] = $entity_info[$key]['label'];
+ }
+ }
+ $this->value_options = $allowed_types;
+ }
+ }
+}
diff --git a/views/entity_translation_handler_filter_language.inc b/views/entity_translation_handler_filter_language.inc
new file mode 100644
index 0000000..7e4b8db
--- /dev/null
+++ b/views/entity_translation_handler_filter_language.inc
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @file
+ * Contains a language filter handler.
+ */
+
+/**
+ * Extends the locale language filter in order for it to work
+ * with the entity translation table structure.
+ */
+class entity_translation_handler_filter_language extends views_handler_filter_locale_language {
+
+ /**
+ * Override the default behaviour, insert an empty string instead of NULL.
+ */
+ function op_empty() {
+ $this->ensure_my_table();
+ if ($this->operator == 'empty') {
+ $operator = "=";
+ }
+ else {
+ $operator = "<>";
+ }
+
+ $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", '', $operator);
+ }
+}
diff --git a/views/entity_translation_handler_filter_translation_exists.inc b/views/entity_translation_handler_filter_translation_exists.inc
new file mode 100644
index 0000000..141008c
--- /dev/null
+++ b/views/entity_translation_handler_filter_translation_exists.inc
@@ -0,0 +1,132 @@
+<?php
+/**
+ * @file
+ * Contains an entity type filter handler.
+ */
+
+/**
+ * This handler determines if a translation exists for a particular translation.
+ */
+class entity_translation_handler_filter_translation_exists extends views_handler_filter_locale_language {
+
+ /**
+ * Add a 'entity_type' option definition.
+ * @see views_handler_field::option:definition()
+ */
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['entity_type'] = array('default' => '', 'translatable' => FALSE);
+ $options['use_filter'] = array('default' => '', 'translatable' => FALSE);
+ $options['filter'] = array('default' => '', 'translatable' => FALSE);
+ return $options;
+ }
+
+ /**
+ * Override the default title for the operators.
+ */
+ function operators() {
+ $operators = parent::operators();
+ $operators['in']['title'] = t('Translation exists');
+ $operators['not in']['title'] = t('Translation doesn\'t exist');
+ return $operators;
+ }
+
+ /**
+ * Add option for setting entity type either directly or through a filter.
+ * @see views_handler_field::options_form()
+ */
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $filters = $this->get_entity_type_filters();
+ if (!empty($filters)) {
+ $form['use_filter'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use an entity type filter.'),
+ '#default_value' => $this->options['use_filter'],
+ );
+ $form['filter'] = array(
+ '#type' => 'select',
+ '#title' => t('Filter'),
+ '#options' => $filters,
+ '#dependency' => array(
+ 'edit-options-use-filter' => array(1)
+ ),
+ '#default_value' => $this->options['filter'],
+ );
+ }
+ $form['entity_type'] = array(
+ '#title' => t('Entity type'),
+ '#type' => 'select',
+ '#options' => $this->get_allowed_types(),
+ '#dependency' => array(
+ 'edit-options-use-filter' => array(0)
+ ),
+ '#default_value' => $this->options['entity_type'],
+ '#description' => t('You have to filter on a particular entity type when you use this filter'),
+ );
+ }
+
+ /**
+ * Get all available entity type filters that can be used to build the query.
+ */
+ function get_entity_type_filters() {
+ // We need to build the query to know about the available fields.
+ $this->view->build();
+ $filters = array();
+ foreach ($this->view->filter as $key => $filter) {
+ // Break if we encounter our filter, the filter must be before this one.
+ if ($filter == $this) {
+ break;
+ }
+ if ($filter instanceof entity_translation_handler_filter_entity_type && count($filter->value) == 1 && empty($filter->options['expose']['multiple'])) {
+ $filters[$key] = $filter->value_title;
+ }
+ }
+ return $filters;
+ }
+
+ /**
+ * Get entity types managed by entity translation.
+ */
+ function get_allowed_types() {
+ $allowed_types_options = variable_get('entity_translation_entity_types');
+ $allowed_types = array();
+ $entity_info = entity_get_info();
+ foreach ($allowed_types_options as $key => $allowed) {
+ if ($allowed) {
+ $allowed_types[$key] = $entity_info[$key]['label'];
+ }
+ }
+ return $allowed_types;
+ }
+
+ /**
+ * Override the default behaviour of the handler.
+ */
+ function query() {
+ $this->ensure_my_table();
+ // We need a subquery to determine not in.
+ if ($this->operator == 'not in') {
+ $entity_type = 'node';
+ if ($this->options['use_filter'] && isset($this->view->filter[$this->options['filter']])) {
+ $filter = $this->view->filter[$this->options['filter']];
+ $entity_type = current($filter->value);
+ }
+ else {
+ $this->query->add_where($this->options['group'], "$this->table_alias.entity_type", $this->options['entity_type'], '=');
+ $entity_type = $this->options['entity_type'];
+ }
+ $query = db_select('entity_translation', 'es')
+ ->condition('entity_type', $entity_type)
+ ->condition('language', $this->value);
+ $query->addField('es', 'entity_id');
+ $this->query->add_where($this->options['group'], "$this->table_alias.entity_id", $query, $this->operator);
+ }
+ // We can determine if a translation exists without a subquery.
+ else {
+ $value = array_keys($this->value);
+ $this->query->add_where($this->options['group'], "$this->table_alias.source", '', '<>');
+ $this->query->add_where($this->options['group'], "$this->table_alias.language", array_values($this->value), $this->operator);
+ }
+ }
+}
diff --git a/views/entity_translation_handler_relationship.inc b/views/entity_translation_handler_relationship.inc
new file mode 100644
index 0000000..52da2b5
--- /dev/null
+++ b/views/entity_translation_handler_relationship.inc
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @file
+ * Contains the relationship plugin for relating entities to translation metadata.
+ */
+
+/**
+ * Add a relationship to the entity translation table.
+ */
+class entity_translation_handler_relationship extends views_handler_relationship {
+
+ /**
+ * Add a relationship to the entity_translation table.
+ */
+ function query() {
+ $this->ensure_my_table();
+ $def = $this->definition;
+ $def['table'] = 'entity_translation';
+ $def['field'] = 'entity_id';
+ $def['type'] = empty($this->options['required']) ? 'LEFT' : 'INNER';
+ $join = new views_join();
+ $join->definition = $def;
+ $join->construct();
+ $join->adjusted = TRUE;
+ // use a short alias for the table.
+ $alias = $def['table'] . '_' . $this->table;
+ // We need to add a condition on entity type to the join
+ // to avoid getting relationships to entities with other types.
+ $join->extra = "$alias.entity_type = '{$def['entity type']}'";
+ $this->alias = $this->query->add_relationship($alias, $join, 'entity_translation', $this->relationship);
+ }
+}
--
1.7.5.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment