From 472f2ff3d9a4081edc3d14cf8570d6a32786c8ec Mon Sep 17 00:00:00 2001
From: Sascha Grossenbacher <saschagros@gmail.com>
Date: Thu, 15 Sep 2011 18:51:03 +0200
Subject: [PATCH] Issue #1258018 by Berdir: Make the userpoints_transaction entity fieldable.

---
 userpoints.admin.inc       |   41 ++++++++++++++++++++++-----------
 userpoints.module          |   12 ++++++++-
 userpoints.pages.inc       |    4 +++
 userpoints.transaction.inc |   53 ++++++++++++++++---------------------------
 4 files changed, 61 insertions(+), 49 deletions(-)

diff --git a/userpoints.admin.inc b/userpoints.admin.inc
index 17d1d79..59e5101 100644
--- a/userpoints.admin.inc
+++ b/userpoints.admin.inc
@@ -28,22 +28,18 @@ function userpoints_admin_txn($form, &$form_state, $mode, $txn = NULL) {
     drupal_set_title(t('Edit !points transaction', userpoints_translation()));
     $timestamp = format_date($txn->time_stamp, 'custom', 'Y-m-d H:i:s O');
     $txn_user = $txn->user;
-
-    $form['txn'] = array(
-      '#type' => 'value',
-      '#value' => $txn,
-    );
   }
   elseif ($mode == 'add') {
     drupal_set_title(t('Add !points', userpoints_translation()));
     if ($txn) {
       $txn_user = user_load($txn);
     }
-    $txn = NULL;
+    $txn = new UserpointsTransaction();
   }
+  $form_state['userpoints_transaction'] = $txn;
 
   // If this transaction is read only, disable all fields.
-  $disable = $txn && $txn->isReadOnly();
+  $disable = $txn->isReadOnly();
 
   if ($disable) {
     drupal_set_message(t('This transaction is read only and can not be changed.'), 'warning');
@@ -170,7 +166,7 @@ function userpoints_admin_txn($form, &$form_state, $mode, $txn = NULL) {
   $form['reason']['operation'] = array(
       '#type' => 'textfield',
       '#title' => t('Operation'),
-      '#default_value' => isset($txn) ? $txn->operation : t('admin'),
+      '#default_value' => $txn->getOperation() ? $txn->operation : t('admin'),
       '#maxlength' => 48,
       '#description' => t('The operation type for this transaction (default is %admin). Any value is valid but using a defined operation will cause an auto-generated description (specific to the chosen operation) to be included. This description can be translated into multiple languages.', array('%admin' => t('admin'))),
       '#weight' => 5,
@@ -251,12 +247,18 @@ function userpoints_admin_txn($form, &$form_state, $mode, $txn = NULL) {
       '#default_value' => $mode
   );
 
-  $form['submit'] = array(
+  $form['actions'] = array(
+    '#type' => 'actions',
+  );
+
+  $form['actions']['submit'] = array(
       '#type' => 'submit',
       '#value' => t('Save'),
       '#weight' => 50,
       '#disabled' => $disable,
   );
+
+  field_attach_form('userpoints_transaction', $txn, $form, $form_state);
   return $form;
 }
 /**
@@ -325,6 +327,7 @@ function userpoints_admin_txn_validate($form, &$form_state) {
     form_set_error('time_stamp', t('The provided timestamp is not a valid date.'));
   }
 
+  field_attach_form_validate('userpoints_transaction', $form_state['userpoints_transaction'], $form, $form_state);
 }
 
 /**
@@ -333,11 +336,13 @@ function userpoints_admin_txn_validate($form, &$form_state) {
 function userpoints_admin_txn_submit($form, &$form_state) {
   global $user;
 
+  $transaction = $form_state['userpoints_transaction'];
+
   // Check if this is a new transaction or if we are editing an existing one.
   if ($form_state['values']['mode'] == 'add') {
-
-    // Create a new transaction object.
-    $transaction = userpoints_grant_points($form_state['values']['operation'], $form_state['values']['points'], $form_state['values']['txn_user']->uid)
+    // Set basic properties.
+    $transaction
+      ->setUid($form_state['values']['txn_user']->uid)
       ->setTimestamp($form_state['values']['time_stamp']);
 
     // If the transaction should be moderated, set it to pending.
@@ -356,8 +361,7 @@ function userpoints_admin_txn_submit($form, &$form_state) {
   else {
 
     // Updating an existing transaction, load and update values.
-    $transaction = userpoints_transaction_load($form_state['values']['txn']->txn_id)
-      ->setPoints($form_state['values']['points'])
+    $transaction = $form_state['userpoints_transaction']
       ->setStatus($form_state['values']['status'])
       // We display a custom message instead of the default.
       ->setMessage(t('Changes to the !points transaction have been saved.', userpoints_translation()));
@@ -375,9 +379,18 @@ function userpoints_admin_txn_submit($form, &$form_state) {
     }
   }
 
+  // Attach field information directly to the userpoints transaction object.
+  foreach (field_info_instances('userpoints_transaction', 'userpoints_transaction') as $instance) {
+    $field_name = $instance['field_name'];
+    $transaction->$field_name = $form_state['values'][$field_name];
+  }
+
+  field_attach_submit('userpoints_transaction', $transaction, $form, $form_state);
+
   // Set common properties and save the transaction.
   $transaction
     ->setTid($form_state['values']['tid'])
+    ->setPoints($form_state['values']['points'])
     ->setOperation($form_state['values']['operation'])
     ->setReference($form_state['values']['reference'])
     ->setDescription($form_state['values']['description'])
diff --git a/userpoints.module b/userpoints.module
index db1591f..1763410 100644
--- a/userpoints.module
+++ b/userpoints.module
@@ -1470,11 +1470,19 @@ function userpoints_entity_info() {
       'controller class' => 'UserpointsTransactionController',
       'base table' => 'userpoints_txn',
       'uri callback' => 'userpoints_transaction_uri_callback',
-      'fieldable' => FALSE,
+      'fieldable' => TRUE,
       'entity keys' => array(
         'id' => 'txn_id',
       ),
-      'bundles' => array(),
+      'bundles' => array(
+        'userpoints_transaction' => array(
+          'label' => t('Default bundle'),
+          'admin' => array(
+            'path' => 'admin/config/people/userpoints',
+            'access arguments' => array('administer userpoints'),
+          ),
+        ),
+      ),
       'view modes' => array(
         'full' => array(
           'label' => t('Full content'),
diff --git a/userpoints.pages.inc b/userpoints.pages.inc
index 62f7071..10c27c2 100644
--- a/userpoints.pages.inc
+++ b/userpoints.pages.inc
@@ -218,6 +218,7 @@ function userpoints_list_users($form, &$form_state, $tid = NULL) {
 function userpoints_view_transaction($transaction) {
   drupal_add_css(drupal_get_path('module', 'userpoints') . '/userpoints.css');
 
+  field_attach_prepare_view('userpoints_transaction', array($transaction->getTxnId() => $transaction), 'full');
   drupal_set_title(t('View transaction #@txn_id', array('@txn_id' => $transaction->txn_id)));
 
   $css_stati = array(
@@ -437,5 +438,8 @@ function userpoints_view_transaction($transaction) {
       '#attributes' => array('class' => array('userpoints-item-actions')),
     );
   }
+
+  $content += field_attach_view('userpoints_transaction', $transaction, 'full');
+
   return $content;
 }
\ No newline at end of file
diff --git a/userpoints.transaction.inc b/userpoints.transaction.inc
index 07869c7..a064462 100644
--- a/userpoints.transaction.inc
+++ b/userpoints.transaction.inc
@@ -759,11 +759,13 @@ class UserpointsTransaction {
       throw new UserpointsTransactionDeniedException($this->getDenyReasons());
     }
 
+    field_attach_presave('userpoints_transaction', $this);
     if (empty($this->txn_id)) {
       // This is a new transaction, save.
       $this->txn_id = db_insert('userpoints_txn')
           ->fields($this->fields)
           ->execute();
+      field_attach_insert('userpoints_transaction', $this);
     }
     else {
       // Existing transaction, update.
@@ -771,6 +773,7 @@ class UserpointsTransaction {
         ->condition('txn_id', $this->txn_id)
         ->fields($this->fields)
         ->execute();
+      field_attach_update('userpoints_transaction', $this);
     }
 
     // Update totals if the transaction is approved and not expired.
@@ -1211,7 +1214,7 @@ class UserpointsTransaction {
    */
   function __destruct() {
     // Automatically save new transactions to improve DX.
-    if (!$this->getTxnId() && !$this->isAborted()) {
+    if (!$this->getTxnId() && !$this->isAborted() && $this->getPoints() && $this->getUid()) {
       $this->save();
     }
   }
@@ -1220,21 +1223,15 @@ class UserpointsTransaction {
    * Magic function to allow access to property by name.
    */
   function __get($name) {
-
-    // Compatibility with dpm().
-    if (strpos($name, 'krumo') !== FALSE) {
-      if (!isset($this->$name)) {
-        $this->$name = NULL;
-      }
-      return $this->$name;
-    }
-
     $method = 'get' . str_replace('_', '', $name);
     if (method_exists($this, $method)) {
       return $this->$method();
     }
     else {
-      throw new UserpointsInvalidPropertyException($name);
+      if (!isset($this->$name)) {
+        $this->$name = NULL;
+      }
+      return $this->$name;
     }
   }
 
@@ -1253,31 +1250,21 @@ class UserpointsTransaction {
       return $this->$name = $value;
     }
   }
+
+  /**
+   * Magic method for isset($transaction->$property) calls.
+   */
+  public function __isset($name) {
+    $method = 'get' . str_replace('_', '', $name);
+    if (method_exists($this, $method)) {
+      return TRUE;
+    }
+    return FALSE;
+  }
 }
 
 /**
- * This exception is thrown when a pr{ "rules_userpoints_transaction_after_test_rule" : {
-        "LABEL" : "Userpoints Transaction After Test rule",
-        "PLUGIN" : "reaction rule",
-        "REQUIRES" : [ "rules", "userpoints_rules" ],
-        "ON" : [ "userpoints_event_points_awarded_after" ],
-        "IF" : [
-          { "data_is" : {
-              "data" : [ "userpoints-transaction:operation" ],
-              "value" : "userpoints_rules_trigger_after_rule"
-            }
-          }
-        ],
-        "DO" : [
-          { "data_set" : { "data" : [ "userpoints-transaction:status" ], "value" : "1" } },
-          { "data_set" : {
-              "data" : [ "userpoints-transaction:reference" ],
-              "value" : "Transaction was set to pending through rules."
-            }
-          }
-        ]
-      }
-    }operty is changed after a saved transaction
+ * This exception is thrown when a property is changed after a saved transaction
  * has been approved or declined.
  */
 class UserpointsChangeException extends Exception {
-- 
1.7.4.1

