diff --git feedback-entry.tpl.php feedback-entry.tpl.php
new file mode 100644
index 0000000..4059a7f
--- /dev/null
+++ feedback-entry.tpl.php
@@ -0,0 +1,30 @@
+
+
diff --git feedback.admin.inc feedback.admin.inc
index 6256b76..dff926d 100644
--- feedback.admin.inc
+++ feedback.admin.inc
@@ -125,3 +125,105 @@ function feedback_admin_view_form_submit($form, &$form_state) {
}
}
+/**
+ * Form builder; The general feedback settings form.
+ *
+ * Currently this form is a necessity as a parent for the field local tasks.
+ *
+ * @ingroup forms
+ */
+function feedback_admin_settings_form($form, &$form_state) {
+ drupal_set_message(t('There are no feedback settings yet, but you can configure fields.'));
+ $form = array();
+ return $form;
+}
+
+/**
+ * Generate an array for rendering the given entry.
+ *
+ * @param $entry
+ * A feedback entry object.
+ * @param $view_mode
+ * View mode, e.g. 'full'.
+ * @param $langcode
+ * (optional) A language code to use for rendering. Defaults to the global
+ * content language of the current request.
+ *
+ * @return
+ * An array as expected by drupal_render().
+ */
+function feedback_view($entry, $view_mode = 'full', $langcode = NULL) {
+ if (!isset($langcode)) {
+ $langcode = $GLOBALS['language_content']->language;
+ }
+
+ // Retrieve all entry fields and attach to $entry->content.
+ feedback_build_content($entry, $view_mode, $langcode);
+
+ $build = $entry->content;
+ // We don't need duplicate rendering info in entry->content.
+ unset($entry->content);
+
+ $build += array(
+ '#theme' => 'feedback_entry',
+ '#entry' => $entry,
+ '#view_mode' => $view_mode,
+ '#language' => $langcode,
+ );
+
+ // Allow modules to modify the structured entry.
+ $type = 'feedback';
+ drupal_alter(array('feedback_view', 'entity_view'), $build, $type);
+
+ return $build;
+}
+
+/**
+ * Builds a structured array representing the feedback message content.
+ *
+ * @param $entry
+ * A feedback entry object.
+ * @param $view_mode
+ * View mode, e.g. 'full'.
+ * @param $langcode
+ * (optional) A language code to use for rendering. Defaults to the global
+ * content language of the current request.
+ */
+function feedback_build_content($entry, $view_mode = 'full', $langcode = NULL) {
+ if (!isset($langcode)) {
+ $langcode = $GLOBALS['language_content']->language;
+ }
+
+ // Build fields content.
+ field_attach_prepare_view('feedback', array($entry->fid => $entry), $view_mode);
+ entity_prepare_view('feedback', array($entry->fid => $entry));
+ $entry->content = field_attach_view('feedback', $entry, $view_mode, $langcode);
+
+ module_invoke_all('feedback_view', $entry, $view_mode, $langcode);
+ module_invoke_all('entity_view', $entry, 'feedback', $view_mode, $langcode);
+}
+
+/**
+ * Process variables for feedback-entry.tpl.php.
+ *
+ * The $variables array contains the following arguments:
+ * - $entry
+ *
+ * @see feedback-entry.tpl.php
+ */
+function template_preprocess_feedback_entry(&$variables) {
+ foreach (element_children($variables['elements']) as $key) {
+ $variables['content'][$key] = $variables['elements'][$key];
+ }
+
+ $entry = $variables['elements']['#entry'];
+
+ // Preprocess fields.
+ field_attach_preprocess('feedback', $entry, $variables['elements'], $variables);
+
+ $variables['location'] = l($entry->location, $entry->url);
+ $variables['date'] = format_date($entry->timestamp, 'small');
+ $variables['account'] = format_username($entry);
+ $variables['message'] = feedback_format_message($entry);
+}
+
diff --git feedback.api.php feedback.api.php
index 290307f..824569e 100644
--- feedback.api.php
+++ feedback.api.php
@@ -24,6 +24,19 @@ function hook_feedback_load($entries) {
}
/**
+ * Act on a feedback entry before it is saved.
+ *
+ * Modules implementing this hook can act on the feedback entry object before it
+ * is inserted or updated.
+ *
+ * @param $entry
+ * The feedback entry object.
+ */
+function hook_feedback_presave($entry) {
+ $entry->foo = 'bar';
+}
+
+/**
* Respond to creation of a new feedback entry.
*
* @param $entry
@@ -70,5 +83,51 @@ function hook_feedback_delete($entry) {
}
/**
+ * The feedback entry is being displayed.
+ *
+ * The module should format its custom additions for display and add them to the
+ * $entry->content array.
+ *
+ * @param $entry
+ * The feedback entry object.
+ * @param $view_mode
+ * View mode, e.g. 'full'.
+ * @param $langcode
+ * The language code used for rendering.
+ *
+ * @see hook_feedback_view_alter()
+ * @see hook_entity_view()
+ */
+function hook_feedback_view($entry, $view_mode, $langcode) {
+ $entry->content['foo'] = array(
+ '#markup' => t('Bar'),
+ );
+}
+
+/**
+ * The feedback entry was built; the module may modify the structured content.
+ *
+ * This hook is called after the content has been assembled in a structured
+ * array and may be used for doing processing which requires that the complete
+ * content structure has been built.
+ *
+ * @param $build
+ * A renderable array representing the feedback entry.
+ *
+ * @see feedback_view()
+ * @see hook_entity_view_alter()
+ */
+function hook_feedback_view_alter(&$build) {
+ // Check for the existence of a field added by another module.
+ if (isset($build['an_additional_field'])) {
+ // Change its weight.
+ $build['an_additional_field']['#weight'] = -10;
+ }
+
+ // Add a #post_render callback to act on the rendered HTML of the entry.
+ $build['#post_render'][] = 'my_module_feedback_post_render';
+}
+
+/**
* @} End of "addtogroup hooks".
*/
diff --git feedback.controller.inc feedback.controller.inc
new file mode 100644
index 0000000..d10f950
--- /dev/null
+++ feedback.controller.inc
@@ -0,0 +1,23 @@
+innerJoin('users', 'u', 'base.uid = u.uid');
+ $query->fields('u', array('name'));
+ return $query;
+ }
+}
\ No newline at end of file
diff --git feedback.info feedback.info
index c42773f..db396bb 100644
--- feedback.info
+++ feedback.info
@@ -2,4 +2,6 @@ name = Feedback
description = Allows site visitors and users to report issues about this site.
package = Development
core = 7.x
+configure = admin/config/user-interface/feedback
+files[] = feedback.controller.inc
files[] = tests/feedback.test
diff --git feedback.module feedback.module
index 65c2acd..c216a20 100644
--- feedback.module
+++ feedback.module
@@ -6,6 +6,66 @@
*/
/**
+ * Implements hook_theme().
+ */
+function feedback_theme() {
+ return array(
+ 'feedback_admin_view_form' => array(
+ 'render element' => 'form',
+ ),
+ 'feedback_entry' => array(
+ 'render element' => 'elements',
+ 'template' => 'feedback-entry',
+ 'file' => 'feedback.admin.inc',
+ ),
+ );
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function feedback_entity_info() {
+ $return = array(
+ 'feedback' => array(
+ 'label' => t('Feedback'),
+ 'controller class' => 'FeedbackController',
+ 'base table' => 'feedback',
+ 'uri callback' => 'feedback_uri',
+ 'fieldable' => TRUE,
+ 'entity keys' => array(
+ 'id' => 'fid',
+ ),
+ 'bundles' => array(
+ 'feedback' => array(
+ 'label' => t('Feedback'),
+ 'admin' => array(
+ 'path' => 'admin/config/user-interface/feedback',
+ 'access arguments' => array('administer feedback'),
+ ),
+ ),
+ ),
+ 'view modes' => array(
+ 'full' => array(
+ 'label' => t('Full feedback entry'),
+ 'custom settings' => FALSE,
+ ),
+ ),
+ ),
+ );
+
+ return $return;
+}
+
+/**
+ * Entity uri callback.
+ */
+function feedback_uri($entry) {
+ return array(
+ 'path' => 'admin/reports/feedback/' . $entry->fid,
+ );
+}
+
+/**
* Implements hook_permission().
*/
function feedback_permission() {
@@ -18,16 +78,8 @@ function feedback_permission() {
'title' => t('View feedback messages'),
'description' => t('View, process, and delete submitted feedback messages.'),
),
- );
-}
-
-/**
- * Implements hook_theme().
- */
-function feedback_theme() {
- return array(
- 'feedback_admin_view_form' => array(
- 'render element' => 'form',
+ 'administer feedback' => array(
+ 'title' => t('Administer feedback settings'),
),
);
}
@@ -44,6 +96,27 @@ function feedback_menu() {
'access arguments' => array('view feedback messages'),
'file' => 'feedback.admin.inc',
);
+ $items['admin/reports/feedback/%feedback'] = array(
+ 'title' => 'Feedback entry',
+ 'page callback' => 'feedback_view',
+ 'page arguments' => array(3),
+ 'access arguments' => array('view feedback messages'),
+ 'file' => 'feedback.admin.inc',
+ );
+ $items['admin/config/user-interface/feedback'] = array(
+ 'title' => 'Feedback',
+ 'description' => 'Administer feedback settings.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('feedback_admin_settings_form'),
+ 'access arguments' => array('administer feedback'),
+ 'file' => 'feedback.admin.inc',
+ );
+ $items['admin/config/user-interface/feedback/settings'] = array(
+ 'title' => 'Settings',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'weight' => -10,
+ );
+
return $items;
}
@@ -123,10 +196,10 @@ function feedback_form($form, &$form_state) {
);
if (user_access('view feedback messages')) {
if (arg(0) != 'node') {
- $feedbacks = feedback_load_multiple(array(), array('f.status' => 0, 'f.location_masked' => feedback_mask_path($_GET['q'])));
+ $feedbacks = feedback_load_multiple(array(), array('status' => 0, 'location_masked' => feedback_mask_path($_GET['q'])));
}
else {
- $feedbacks = feedback_load_multiple(array(), array('f.status' => 0, 'f.location' => $_GET['q']));
+ $feedbacks = feedback_load_multiple(array(), array('status' => 0, 'location' => $_GET['q']));
}
if ($feedbacks) {
$rows = '';
@@ -149,6 +222,10 @@ function feedback_form($form, &$form_state) {
'#required' => TRUE,
'#wysiwyg' => FALSE,
);
+
+ $entry = new stdClass();
+ field_attach_form('feedback', $entry, $form, $form_state);
+
$form['actions'] = array(
'#type' => 'actions',
// Without clearfix, the AJAX throbber wraps in an ugly way.
@@ -177,6 +254,7 @@ function feedback_form($form, &$form_state) {
*/
function feedback_form_submit($form, &$form_state) {
$entry = new stdClass();
+ entity_form_submit_build_entity('feedback', $entry, $form, $form_state);
$entry->message = $form_state['values']['message'];
$entry->location = $form_state['values']['location'];
feedback_save($entry);
@@ -241,6 +319,10 @@ function feedback_format_message($entry) {
$message .= '(' . check_plain($entry->useragent) . ')
';
}
}
+ $uri = entity_uri('feedback', $entry);
+ if ($uri['path'] != $_GET['q']) {
+ $message .= l("view full", $uri['path']);
+ }
return $message;
}
@@ -273,23 +355,14 @@ function feedback_load($fid) {
*
* @return
* An array of feedback entry objects indexed by fid.
+ *
+ * @see hook_feedback_load()
+ * @see feedback_load()
+ * @see entity_load()
+ * @see EntityFieldQuery
*/
function feedback_load_multiple($fids = array(), $conditions = array()) {
- $query = db_select('feedback', 'f')->fields('f');
- $query->join('users', 'u', 'f.uid = u.uid');
- $query->fields('u', array('name'));
-
- if (!empty($fids)) {
- $query->condition('fid', $fids, 'IN');
- }
- if (!empty($conditions)) {
- foreach ($conditions as $key => $value) {
- $query->condition($key, $value);
- }
- }
- $entries = $query->execute()->fetchAllAssoc('fid');
- module_invoke_all('feedback_load', $entries);
- return $entries;
+ return entity_load('feedback', $fids, $conditions);
}
/**
@@ -305,30 +378,47 @@ function feedback_load_multiple($fids = array(), $conditions = array()) {
function feedback_save($entry) {
global $user;
+ // Load the stored entity, if any.
+ if (!empty($entry->fid) && !isset($entry->original)) {
+ $entry->original = entity_load_unchanged('feedback', $entry->fid);
+ }
+
+ field_attach_presave('feedback', $entry);
+
+ // Allow modules to alter the feedback entry before saving.
+ module_invoke_all('feedback_presave', $entry);
+ module_invoke_all('entity_presave', $entry, 'feedback');
+
if (empty($entry->fid)) {
- if (!isset($entry->uid)) {
- $entry->uid = $user->uid;
- }
$entry->message = trim($entry->message);
- if (!isset($entry->location_masked)) {
- $entry->location_masked = feedback_mask_path($entry->location);
- }
- if (!isset($entry->url)) {
- $entry->url = url($entry->location, array('absolute' => TRUE));
- }
- if (!isset($entry->timestamp)) {
- $entry->timestamp = REQUEST_TIME;
- }
- if (!isset($entry->useragent)) {
- $entry->useragent = $_SERVER['HTTP_USER_AGENT'];
+
+ $defaults = array(
+ 'uid' => $user->uid,
+ 'location_masked' => feedback_mask_path($entry->location),
+ 'url' => url($entry->location, array('absolute' => TRUE)),
+ 'timestamp' => REQUEST_TIME,
+ 'useragent' => $_SERVER['HTTP_USER_AGENT'],
+ );
+ foreach ($defaults as $key => $default) {
+ if (!isset($entry->$key)) {
+ $entry->$key = $default;
+ }
}
+
$status = drupal_write_record('feedback', $entry);
+ field_attach_insert('feedback', $entry);
module_invoke_all('feedback_insert', $entry);
+ module_invoke_all('entity_insert', $entry, 'feedback');
}
else {
$status = drupal_write_record('feedback', $entry, 'fid');
+
+ field_attach_update('feedback', $entry);
module_invoke_all('feedback_update', $entry);
+ module_invoke_all('entity_update', $entry, 'feedback');
}
+ unset($entry->original);
+
return $status;
}
@@ -352,7 +442,9 @@ function feedback_delete_multiple($fids) {
if (!empty($fids)) {
$entries = feedback_load_multiple($fids);
foreach ($entries as $fid => $entry) {
+ field_attach_delete('feedback', $entry);
module_invoke_all('feedback_delete', $entry);
+ module_invoke_all('entity_delete', $entry, 'feedback');
}
db_delete('feedback')
->condition('fid', $fids, 'IN')