class editableviews_style_helper in Editable Views 7
Helper class for the style plugin.
This abstracts out a number of things the style plugin needs to do, in order that other style plugins can use them too.
Hierarchy
- class \editableviews_style_helper
Expanded class hierarchy of editableviews_style_helper
File
- ./
editableviews_plugin_style_row_edit_table.inc, line 348
View source
class editableviews_style_helper {
/**
* A lookup from relationships to the data needed to load their entities.
*
* This is an array of the relationships on the view which correspond to
* entity base tables, including the base table (as a pseudo-relationship).
* The key is the relationship id (in the case of the base table, this is just
* the table name itself). Each value is an array containing:
* - 'entity_type': The entity type this relationship brings to the view.
* - 'id_field_alias': The field alias of the field on the view in which to
* find the entity's ID. This field is ensured by our query().
*/
public $relationship_entity_fields = array();
function __construct(&$plugin) {
$this->plugin =& $plugin;
}
/**
* Provide common options for editable style plugins.
*/
function options_form(&$form, &$form_state) {
// Add a fieldset to allow setting of a creation bundle for all the
// relationships that are non-required. This is because a non-required
// relationship may cause empty data in the result, and if this has editable
// fields, then entering data into those field's form elements causes the
// creation of a new entity. Which we need a bundle for.
$relationship_handlers = $this->plugin->display->handler
->get_handlers('relationship');
// Get our edit field handlers.
$edit_field_handlers = $this->plugin
->get_edit_field_handlers();
// Collect the relationships these are on.
$edit_relationship_handlers = array();
foreach ($edit_field_handlers as $field_handler_id => $field_handler) {
// Because we're not in the process of querying, the relationship is only
// set in the options.
$relationship_id = $field_handler->options['relationship'];
// Skip edit field handlers that are on the base.
if ($relationship_id == 'none') {
continue;
}
// Argh, do we need to contend with the alias of the relationship here??
// Skip a relationship that is required: these will never provide an empty
// row, and so never require entity creation.
if ($relationship_handlers[$relationship_id]->options['required']) {
continue;
}
// If we're still here, this is a relationship we need to consider.
$edit_relationship_handlers[$relationship_id] = $relationship_handlers[$relationship_id];
}
// Only show this fieldset if there are relationships to consider.
if (count($edit_relationship_handlers)) {
$form['relationship_creation_bundle'] = array(
'#type' => 'fieldset',
'#title' => t('Relationship entity creation bundles'),
'#description' => t('A relationship which is set to not required may produce empty form elements, which thus require the creation of a new entity if populated with data. The bundle for these new entities must be specified here.'),
'#weight' => -1,
);
foreach ($edit_relationship_handlers as $relationship_id => $relationship_handler) {
// The 'base' of a relationship is the table it brings.
$table = $relationship_handler->definition['base'];
// Get the entity type from the table.
$table_data = views_fetch_data($table);
$entity_type = $table_data['table']['entity type'];
$entity_info = entity_get_info($entity_type);
$options = array();
foreach ($entity_info['bundles'] as $bundle => $bundle_info) {
$options[$bundle] = $bundle_info['label'];
}
$form['relationship_creation_bundle'][$relationship_id] = array(
'#type' => 'select',
'#title' => t('Bundle for new entities created on %label', array(
'%label' => $relationship_handler->options['label'],
)),
'#description' => t('Select the %entity entity bundle for entities created on this relationship.', array(
'%entity' => $entity_info['label'],
)),
'#options' => $options,
'#required' => TRUE,
);
// We have to check the default value, as the key in the array is variable
// because it's the relationship handler ID. That means that Views won't
// have it set in option_definition().
if (isset($this->plugin->options['relationship_creation_bundle'][$relationship_id])) {
$form['relationship_creation_bundle'][$relationship_id]['#default_value'] = $this->plugin->options['relationship_creation_bundle'][$relationship_id];
}
}
}
$form['save_messages'] = array(
'#type' => 'select',
'#title' => t("Save messages"),
'#description' => t('The messages to show the user when the view form is saved.'),
'#options' => array(
'none' => t('Show no messages'),
'summary' => t('Show a single message summarizing the changes'),
'individual' => t('Show a message for each saved entity'),
),
'#default_value' => $this->plugin->options['save_messages'],
);
$form['batch'] = array(
'#type' => 'checkbox',
'#title' => t("Enable batch support"),
'#description' => t('Use Batch API to save huge data.'),
'#default_value' => $this->plugin->options['batch'],
);
$form['batch_size'] = array(
'#type' => 'textfield',
'#title' => t("Batch size"),
'#description' => t('Number of entities to process in each batch step.'),
'#default_value' => $this->plugin->options['batch_size'],
'#states' => array(
'visible' => array(
':input[name="style_options[batch]"]' => array(
'checked' => TRUE,
),
),
),
);
}
/**
* Add anything to the query that we might need to.
*
* For the base and each relationship that brings an entity table, add the
* entity ID field for that entity. This ensures that we can load the entities
* when we need to get form elements for them.
*
* We do this for all relationships, not just those which have editable fields
* on them, because we may need access to entities that editable field
* entities need to point to when creating entities.
*/
function query() {
// For each relationship that provides an entity table (including the base
// pseudo-relationship), add the field for that entity's ID.
$base_table = $this->plugin->view->base_table;
// Do the View base first.
$table_data = views_fetch_data($this->plugin->view->base_table);
if (isset($table_data['table']['entity type'])) {
// We don't need to ensure this field is on the query: the id field on
// the base table always is.
$this->relationship_entity_fields[$base_table] = array(
'entity_type' => $table_data['table']['entity type'],
// We don't need to find an alias for a field on the base.
'id_field_alias' => $table_data['table']['base']['field'],
);
}
// Now the relationships.
$relationship_handlers = $this->plugin->display->handler
->get_handlers('relationship');
foreach ($relationship_handlers as $relationship_id => $relationship_handler) {
//dsm($relationship_handler, $relationship_id);
// The 'base' of a relationship is the table it brings.
$table = $relationship_handler->definition['base'];
// Get the entity type from the table.
$table_data = views_fetch_data($table);
if (!isset($table_data['table']['entity type'])) {
// Not an entity base table relationship: skip it.
continue;
}
// Get the entity type and the views field that corresponds to the entity
// id from the table definition.
//dsm($table_data['table'], 'table data');
$entity_type = $table_data['table']['entity type'];
$entity_id_field = $table_data['table']['base']['field'];
// Force the 're
if ($relationship_handler->options['relationship'] == 'none') {
$relationship_relationship = $base_table;
}
else {
$relationship_relationship = $relationship_handler->options['relationship'];
}
//dsm($relationship_relationship, '$relationship_relationship');
// We want the alias for the table the relationship brings, not the table
// it sits on.
$table_alias = $relationship_handler->alias;
//dsm("$relationship_id brings $entity_type, $entity_id_field.\ntable alias is $table_alias");
$entity_id_field_alias = $this->plugin->view->query
->add_field($table_alias, $entity_id_field);
$this->relationship_entity_fields[$relationship_id] = array(
'entity_type' => $entity_type,
'id_field_alias' => $entity_id_field_alias,
);
}
//dsm($this->relationship_entity_fields);
}
/**
* Returns a new (unsaved) entity for the given relationship ID.
*
* This is needed when editable field handlers are on a non-required
* relationship, and a particular result row has no data there. We create a
* new entity for FieldAPI to work on, and potentially save it on submission
* if the user enters data.
*
* @param $relationship_id
* The id of the relationship that requires a new entity.
*
* @return
* A new, unsaved entity. The entity type is implied by the handler, and
* should be known by the caller. The bundle will be set on this, given by
* the style plugin's options.
*/
function entity_create($relationship_id) {
$entity_type = $this->relationship_entity_fields[$relationship_id]['entity_type'];
// This is complex. We know the entity type, but we need to be told
// the bundle: that's one for the plugin settings.
// Then when it's created, we need to know how to set the relationship
// field.
$entity_info = entity_get_info($entity_type);
// Assume this exists, as it must do if the entity is fieldable, and
// if your entity is not fieldable, what are you doing here? ;)
$bundle_key = $entity_info['entity keys']['bundle'];
$values = array(
// The bundle of the new entity is set in the options for this
// style plugin. This has to be set by the user, because there is
// absolutely no other way to sniff this out!
// TODO: cloud cuckoo land, but a form element field to specify
// the bundle for each row would be nice!
$bundle_key => $this->plugin->options['relationship_creation_bundle'][$relationship_id],
);
// Just a little bit of sugar to save this having to be done in a custom
// form submit handler: for nodes and comments, set the uid property
// to the current user. We would do this with anything that has a uid
// property, but entity_get_property_info() calls it 'author' and it's just
// starting to get faffy now.
if ($entity_type == 'node' || $entity_type == 'comment') {
$values['uid'] = $GLOBALS['user']->uid;
}
$entity = entity_create($entity_type, $values);
// Add our own property to the entity, where we keep track of the properties
// that are exposed as form elements in the view. This is how we will
// determine whether or not to save it when the form is submitted.
$entity->editableviews_exposed_fields = array();
// Add our own property to specify whether this needs to be saved or not.
// @see editableviews_entity_form_submit_build_values()
$entity->editableviews_needs_save = FALSE;
return $entity;
}
/**
* Sets the properties so that new entities connect to existing ones.
*
* For a forward relationship, the existing entity must know it has to point
* to the new entity once it has been saved.
* For a reverse relationship, the new entity must have the right property set
* (e.g. an entityreference field) so that it point back to the existing
* entity.
*
* @param $result_entities
* The array of result entities from the style plugin. Passed by reference
* so the entities can be altered. (TODO: is this actually needed??)
* @param $results_coordinates
* The combined coordinates array, containing both the forward and reverse
* lookups for entities and results.
* @see editableviews_plugin_style_row_edit_table::get_form() for details.
* @param $edit_field_handlers_grouped
* The edit field handlers, grouped by relationship handler ID.
*/
function connect_new_entities(&$result_entities, $results_coordinates, $edit_field_handlers_grouped) {
$relationship_handlers = $this->plugin->display->handler
->get_handlers('relationship');
//dsm($edit_field_handlers_grouped);
//dsm($result_entities);
foreach (array_keys($result_entities) as $entity_type) {
foreach ($result_entities[$entity_type] as $entity_id => $entity) {
// New entities have a non-numeric fake id we just gave them.
if (!is_numeric($entity_id)) {
// Get the views coordinates for this entity.
list($relationship_id, $index) = $results_coordinates['entities_to_results'][$entity_type][$entity_id];
$relationship_handler = $relationship_handlers[$relationship_id];
//dsm($relationship_handler);
// Get the relationship that the relationship is on, so we can then
// get the entity for that relationship.
if (isset($relationship_handler->relationship)) {
$relationship_relationship = $relationship_handler->relationship;
}
else {
$relationship_relationship = $this->plugin->view->base_table;
}
// Only act if the new entity's relationship has editable fields:
// otherwise it's just an empty bunch of table cells, and there's
// nothing to connect to or from.
if (count($edit_field_handlers_grouped[$relationship_relationship]) == 0) {
continue;
}
if ($relationship_handler->definition['editableviews_direction'] == 'forward') {
// Get the entity on our relationship's relationship -- same
// as for reverse.
// Get the entity out of the imaginary Views grid that is on the same
// row as us, and in the $relationship_relationship relationship...
list($referring_entity_type, $referring_entity_id) = $results_coordinates['results_to_entities'][$relationship_relationship][$index];
$referring_entity = $result_entities[$referring_entity_type][$referring_entity_id];
// Store this entity's details on the current, new entity, so that
// when (and if!) we save it, we can go and make the referring
// entity point to it.
$entity->editableviews_future_reference = array(
'entity_type' => $referring_entity_type,
'entity_id' => $referring_entity_id,
'field_name' => $relationship_handler->definition['field_name'],
);
}
else {
// Would be nice to factor this out to a helper method, say
// '$this->new_entity_set_reverse_connection()' but we'd need to
// pass so many variables it's probably just as faffy.
// Get the entity out of the imaginary Views grid that is on the same
// row as us, and in the $relationship_relationship relationship...
list($referred_entity_type, $referred_entity_id) = $results_coordinates['results_to_entities'][$relationship_relationship][$index];
$referred_entity = $result_entities[$referred_entity_type][$referred_entity_id];
// From here on, this is just reverse relationships!
$wrapper = entity_metadata_wrapper($entity_type, $entity);
// This is what we need to set on the new entity in a reverse relationship.
$relationship_field_name = $relationship_handler->definition['field_name'];
// Make the new entity point to the entity on its relationship's
// relationship.
$wrapper->{$relationship_field_name}
->set($referred_entity_id);
}
}
}
}
}
/**
* Get editable field handlers grouped by relationship id.
*/
function get_editable_field_handlers_grouped() {
$editable_field_handlers = $this->plugin
->get_edit_field_handlers();
$editable_field_handlers_grouped = array();
foreach ($editable_field_handlers as $field_handler_id => $field_handler) {
//dsm($field_handler, '$field_handler');
$relationship_id = $field_handler->options['relationship'];
if ($relationship_id == 'none') {
// TODO: tidy up this WTF!
$relationship_id = 'base';
}
$editable_field_handlers_grouped[$relationship_id][$field_handler_id] = $field_handler;
}
return $editable_field_handlers_grouped;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
editableviews_style_helper:: |
public | property | A lookup from relationships to the data needed to load their entities. | |
editableviews_style_helper:: |
function | Sets the properties so that new entities connect to existing ones. | ||
editableviews_style_helper:: |
function | Returns a new (unsaved) entity for the given relationship ID. | ||
editableviews_style_helper:: |
function | Get editable field handlers grouped by relationship id. | ||
editableviews_style_helper:: |
function | Provide common options for editable style plugins. | ||
editableviews_style_helper:: |
function | Add anything to the query that we might need to. | ||
editableviews_style_helper:: |
function |