Added pseudo-random sort order to member list results. Still need to consider impleme...
authorChuck Scott <cscott@gaslightmedia.com>
Tue, 18 Oct 2016 21:03:54 +0000 (17:03 -0400)
committerChuck Scott <cscott@gaslightmedia.com>
Tue, 18 Oct 2016 21:03:54 +0000 (17:03 -0400)
lib/GlmDataAbstract/DataAbstract.php
lib/GlmDataAbstract/documentation.odt
models/front/members/list.php

index 3cbb754..cc4ca08 100755 (executable)
@@ -129,28 +129,37 @@ abstract class GlmDataAbstract
      */
     public $fieldPrefix = '';
     /**
-     * Field processing for various field types
+     * Pseudo-Random Order Key Array - Used for Pseudo-Random database result lists
      *
-     * @var $f is field data
+     * @access private
+     */
+    public $pseudoRandArray = false;
+    /**
+     * Pseudo-Random Order flag
      *
-     * @return void
-     * @access public
+     * @access private
+     */
+    public $pseudoRand = false;
+
+
+    /*
+     * Field processing for various types of fields
      */
 
     // Integer Field Processing
-    function integerField($f)
+    private function integerField($f)
     {
         return 'T.'.$f['field'];
     }
-    function integerOptions($f)
+    private function integerOptions($f)
     {
         return false;
     }
-    function integerOutput($f, $d)
+    private function integerOutput($f, $d)
     {
         return $d;
     }
-    function integerInput($as, $f, $id, $idfield, $op)
+    private function integerInput($as, $f, $id, $idfield, $op)
     {
         // If this is setup for a new entry, then just return default value
         if ($op == 'n') {
@@ -227,7 +236,7 @@ abstract class GlmDataAbstract
 
         return $in;
     }
-    function integerStore($in, $f)
+    private function integerStore($in, $f)
     {
         return $in;
     }
@@ -235,15 +244,15 @@ abstract class GlmDataAbstract
     /*
      * Float Field Processing
      */
-    function floatField($f)
+    private function floatField($f)
     {
         return 'T.'.$f['field'];
     }
-    function floatOptions($f)
+    private function floatOptions($f)
     {
         return false;
     }
-    function floatOutput($f, $d)
+    private function floatOutput($f, $d)
     {
         // if a format is specified
         if (isset($f['output_format']) && $f['output_format']) {
@@ -252,7 +261,7 @@ abstract class GlmDataAbstract
 
         return $d;
     }
-    function floatInput($as, $f, $id, $idfield, $op)
+    private function floatInput($as, $f, $id, $idfield, $op)
     {
         // If this is setup for a new entry, then just return default value
         if ($op == 'n') {
@@ -336,7 +345,7 @@ abstract class GlmDataAbstract
 
         return $in;
     }
-    function floatStore($in, $f)
+    private function floatStore($in, $f)
     {
         return $in;
     }
@@ -344,20 +353,20 @@ abstract class GlmDataAbstract
     /*
      * Money Field Processing
      */
-    function moneyField($f)
+    private function moneyField($f)
     {
         return 'T.'.$f['field'];
     }
-    function moneyOptions($f)
+    private function moneyOptions($f)
     {
         return false;
     }
-    function moneyOutput($f, $d)
+    private function moneyOutput($f, $d)
     {
         return "$".sprintf("%01.2f", $d);
         ;
     }
-    function moneyInput($as, $f, $id, $idfield, $op)
+    private function moneyInput($as, $f, $id, $idfield, $op)
     {
         // If this is setup for a new entry, then just return default value
         if ($op == 'n') {
@@ -434,7 +443,7 @@ abstract class GlmDataAbstract
 
         return $in;
     }
-    function moneyStore($in, $f)
+    private function moneyStore($in, $f)
     {
         return $in;
     }
@@ -442,19 +451,19 @@ abstract class GlmDataAbstract
     /*
      * Percent Field Processing
      */
-    function percentField($f)
+    private function percentField($f)
     {
         return 'T.'.$f['field'];
     }
-    function percentOptions($f)
+    private function percentOptions($f)
     {
         return false;
     }
-    function percentOutput($f, $d)
+    private function percentOutput($f, $d)
     {
         return $d;
     }
-    function percentInput($as, $f, $id, $idfield, $op)
+    private function percentInput($as, $f, $id, $idfield, $op)
     {
         // If this is setup for a new entry, then just return default value
         if ($op == 'n') {
@@ -531,7 +540,7 @@ abstract class GlmDataAbstract
 
         return $in;
     }
-    function percentStore($in, $f)
+    private function percentStore($in, $f)
     {
         return $in;
     }
@@ -539,11 +548,11 @@ abstract class GlmDataAbstract
     /*
      *  Pointer Field Processing
      */
-    function pointerField($f)
+    private function pointerField($f)
     {
         return 'T.'.$f['field'];
     }
-    function pointerOptions($f)
+    private function pointerOptions($f)
     {
 
         // Get ID field of other table - default to 'id'
@@ -564,7 +573,7 @@ abstract class GlmDataAbstract
 
         return $options;
     }
-    function pointerOutput($f, $d, $forEdit = false, $id = false, $idfield = 'id')
+    private function pointerOutput($f, $d, $forEdit = false, $id = false, $idfield = 'id')
     {
 
         /*
@@ -718,7 +727,7 @@ abstract class GlmDataAbstract
 
         return $d;
     }
-    function pointerInput($as, $f, $id, $idfield, $op)
+    private function pointerInput($as, $f, $id, $idfield, $op)
     {
 
         $this->inputFieldStatus = true;
@@ -892,7 +901,7 @@ abstract class GlmDataAbstract
 
         return $r;
     }
-    function pointerStore($in, $f)
+    private function pointerStore($in, $f)
     {
         return $in['value'];
     }
@@ -900,15 +909,15 @@ abstract class GlmDataAbstract
     /*
      * List Field Processing
      */
-    function listField($f)
+    private function listField($f)
     {
         return 'T.'.$f['field'];
     }
-    function listOptions($f)
+    private function listOptions($f)
     {
         return false;
     }
-    function listOutput($f, $d, $forEdit, $id, $idfield, $op)
+    private function listOutput($f, $d, $forEdit, $id, $idfield, $op)
     {
 
         // Check for a list data
@@ -971,7 +980,7 @@ abstract class GlmDataAbstract
         return $r;
 
     }
-    function listInput($as, $f, $id, $idField, $op)
+    private function listInput($as, $f, $id, $idField, $op)
     {
 
         // Check for a list data
@@ -1054,7 +1063,7 @@ abstract class GlmDataAbstract
 
         return $r;
     }
-    function listStore($in, $f)
+    private function listStore($in, $f)
     {
         $keytype = 'text';
 
@@ -1075,15 +1084,15 @@ abstract class GlmDataAbstract
     /*\r
      * Bitmap List Field Processing\r
     */\r
-    function bitmapField($f)\r
+    private function bitmapField($f)\r
     {\r
        return 'T.'.$f['field'];\r
     }\r
-    function bitmapOptions($f)\r
+    private function bitmapOptions($f)\r
     {\r
        return false;\r
     }\r
-    function bitmapOutput($f, $d)\r
+    private function bitmapOutput($f, $d)\r
     {\r
        // Check for a bitmap data\r
        if (!isset($f['bitmap']) || !is_array($f['bitmap'])) {\r
@@ -1127,7 +1136,7 @@ abstract class GlmDataAbstract
        return $r;\r
 \r
     }\r
-    function bitmapInput($as, $f, $id, $idField, $op)\r
+    private function bitmapInput($as, $f, $id, $idField, $op)\r
     {\r
 
                // Check for a bitmap data
@@ -1183,7 +1192,7 @@ abstract class GlmDataAbstract
 \r
        return $r;\r
     }\r
-    function bitmapStore($in, $f)\r
+    private function bitmapStore($in, $f)\r
     {\r
        $keytype = 'text';\r
 \r
@@ -1204,19 +1213,19 @@ abstract class GlmDataAbstract
     /*
      * Text Field Processing
      */
-    function textField($f)
+    private function textField($f)
     {
         return 'T.'.$f['field'];
     }
-    function textOptions($f)
+    private function textOptions($f)
     {
         return false;
     }
-    function textOutput($f, $d)
+    private function textOutput($f, $d)
     {
         return $d;
     }
-    function textInput($as, $f, $id, $idField, $op)
+    private function textInput($as, $f, $id, $idField, $op)
     {
 
         // If this is setup for a new entry, then just return default value
@@ -1321,7 +1330,7 @@ abstract class GlmDataAbstract
 
         return $in;
     }
-    function textStore($in, $f)
+    private function textStore($in, $f)
     {
         $r = "'".addslashes($in)."'";
         return $r;
@@ -1330,20 +1339,20 @@ abstract class GlmDataAbstract
     /*\r
      * Password Field Processing\r
     */\r
-    function passwordField($f)\r
+    private function passwordField($f)\r
     {\r
        return 'T.'.$f['field'];\r
     }\r
-    function passwordOptions($f)\r
+    private function passwordOptions($f)\r
     {\r
        return false;\r
     }\r
-    function passwordOutput($f, $d)\r
+    private function passwordOutput($f, $d)\r
     {
        // No output for a password field\r
        return '';\r
     }\r
-    function passwordInput($as, $f, $id, $idField, $op)\r
+    private function passwordInput($as, $f, $id, $idField, $op)\r
     {\r
        // If this is setup for a new entry, then just return default value\r
        if ($op == 'n') {\r
@@ -1427,7 +1436,7 @@ abstract class GlmDataAbstract
 \r
        return $c;\r
     }\r
-    function passwordStore($in, $f)\r
+    private function passwordStore($in, $f)\r
     {\r
        $r = "'".addslashes($in)."'";\r
        return $r;\r
@@ -1436,15 +1445,15 @@ abstract class GlmDataAbstract
     /*
      * Checkbox Field Processing
      */
-    function checkboxField($f)
+    private function checkboxField($f)
     {
         return 'T.'.$f['field'];
     }
-    function checkboxOptions($f)
+    private function checkboxOptions($f)
     {
         return false;
     }
-    function checkboxOutput($f, $d)
+    private function checkboxOutput($f, $d)
     {
         $list = array(
             0 => array(
@@ -1479,7 +1488,7 @@ abstract class GlmDataAbstract
 
         return $r;
     }
-    function checkboxInput($as, $f, $x, $y, $op)
+    private function checkboxInput($as, $f, $x, $y, $op)
     {
         $list = array(
             0 => array(
@@ -1530,7 +1539,7 @@ abstract class GlmDataAbstract
 
         return $r;
     }
-    function checkboxStore($in, $f)
+    private function checkboxStore($in, $f)
     {
         if ($in['value']) {
             return "true";
@@ -1542,19 +1551,19 @@ abstract class GlmDataAbstract
     /*
      * E-Mail Field Procesing
      */
-    function emailField($f)
+    private function emailField($f)
     {
         return 'T.'.$f['field'];
     }
-    function emailOptions($f)
+    private function emailOptions($f)
     {
         return false;
     }
-    function emailOutput($f, $d)
+    private function emailOutput($f, $d)
     {
         return $d;
     }
-    function emailInput($as, $f, $id, $idfield, $op)
+    private function emailInput($as, $f, $id, $idfield, $op)
     {
         // If this is setup for a new entry, then just return default value
         if ($op == 'n') {
@@ -1611,7 +1620,7 @@ abstract class GlmDataAbstract
 
         return $in;
     }
-    function emailStore($in, $f)
+    private function emailStore($in, $f)
     {
         return "'".addslashes($in)."'";
     }
@@ -1619,15 +1628,15 @@ abstract class GlmDataAbstract
     /*
      * Date Field Processing
      */
-    function dateField($f)
+    private function dateField($f)
     {
         return 'T.'.$f['field'];
     }
-    function dateOptions($f)
+    private function dateOptions($f)
     {
         return false;
     }
-    function dateOutput($f, $d, $forEdit)
+    private function dateOutput($f, $d, $forEdit)
     {
 
         // Check for min/max date values
@@ -1684,7 +1693,7 @@ abstract class GlmDataAbstract
 \r
         return $out;
     }
-    function dateInput($as, $f, $id, $idfield, $op)
+    private function dateInput($as, $f, $id, $idfield, $op)
     {
         $this->inputFieldStatus = true;
 
@@ -1824,7 +1833,7 @@ abstract class GlmDataAbstract
         return $v;
 
     }
-    function dateStore($in, $f)
+    private function dateStore($in, $f)
     {
 
         // Check if there's no date then supply null
@@ -1844,7 +1853,7 @@ abstract class GlmDataAbstract
      * Time Field Processing
      */
     // Support function to build picklists for Time field
-    function buildTimeFieldLists()
+    private function buildTimeFieldLists()
     {
         // Setup hour and minute pick lists
         $hour_list = array();
@@ -1871,15 +1880,15 @@ abstract class GlmDataAbstract
 
         return $time_list;
     }
-    function timeField($f)
+    private function timeField($f)
     {
         return 'T.'.$f['field'];
     }
-    function timeOptions($f)
+    private function timeOptions($f)
     {
         return false;
     }
-    function timeOutput($f, $d)
+    private function timeOutput($f, $d)
     {
         // Default values if no time returned
         $hour = 12;
@@ -1928,7 +1937,7 @@ abstract class GlmDataAbstract
 
         return $r;
     }
-    function timeInput($as, $f, $id, $idfield, $op)
+    private function timeInput($as, $f, $id, $idfield, $op)
     {
         $this->inputFieldStatus = true;
         $hour = 12;
@@ -2059,7 +2068,7 @@ abstract class GlmDataAbstract
 
         return $r;
     }
-    function timeStore($in, $f)
+    private function timeStore($in, $f)
     {
         return "'".$in['time_store']."'";
     }
@@ -2067,15 +2076,15 @@ abstract class GlmDataAbstract
     /*
      * datetime (date and time) Field Processing
      */
-    function datetimeField($f)
+    private function datetimeField($f)
     {
         return 'T.'.$f['field'];
     }
-    function datetimeOptions($f)
+    private function datetimeOptions($f)
     {
         return false;
     }
-    function datetimeOutput($f, $d, $forEdit)
+    private function datetimeOutput($f, $d, $forEdit)
     {
 
         // Check for min/max date values
@@ -2154,7 +2163,7 @@ abstract class GlmDataAbstract
 
         return $out;
     }
-    function datetimeInput($as, $f, $id, $idfield, $op)
+    private function datetimeInput($as, $f, $id, $idfield, $op)
     {
         $this->inputFieldStatus = true;
 
@@ -2297,7 +2306,7 @@ abstract class GlmDataAbstract
             return $v;
 
     }
-    function datetimeStore($in, $f)
+    private function datetimeStore($in, $f)
     {
 
         // Check if there's no date then supply null
@@ -2317,19 +2326,19 @@ abstract class GlmDataAbstract
     /*
      * Phone Field Processing
      */
-    function phoneField($f)
+    private function phoneField($f)
     {
         return 'T.'.$f['field'];
     }
-    function phoneOptions($f)
+    private function phoneOptions($f)
     {
         return false;
     }
-    function phoneOutput($f, $d)
+    private function phoneOutput($f, $d)
     {
         return $d;
     }
-    function phoneInput($as, $f, $id, $idfield, $op)
+    private function phoneInput($as, $f, $id, $idfield, $op)
     {
         // If this is setup for a new entry, then just return default value
         if ($op == 'n') {
@@ -2343,7 +2352,7 @@ abstract class GlmDataAbstract
         $in = $_REQUEST[$as];
         return $in;
     }
-    function phoneStore($in, $f)
+    private function phoneStore($in, $f)
     {
         return "'".addslashes($in)."'";
     }
@@ -2351,19 +2360,19 @@ abstract class GlmDataAbstract
     /*
      * Image Field Processing
      */
-    function imageField($f)
+    private function imageField($f)
     {
         return 'T.'.$f['field'];
     }
-    function imageOptions($f)
+    private function imageOptions($f)
     {
         return false;
     }
-    function imageOutput($f, $d)
+    private function imageOutput($f, $d)
     {
         return $d;
     }
-    function imageInput($as, $f, $id, $idfield, $op)
+    private function imageInput($as, $f, $id, $idfield, $op)
     {
 
         $new = false;
@@ -2498,7 +2507,7 @@ abstract class GlmDataAbstract
 
         return $current_img;
     }
-    function imageStore($in, $f)
+    private function imageStore($in, $f)
     {
         return "'".addslashes($in)."'";
     }
@@ -2506,19 +2515,19 @@ abstract class GlmDataAbstract
     /*
      * Base64 Image Field Processing (for inline images)
      */
-    function b64imageField($f)
+    private function b64imageField($f)
     {
         return 'T.'.$f['field'];
     }
-    function b64imageOptions($f)
+    private function b64imageOptions($f)
     {
         return false;
     }
-    function b64imageOutput($f, $d)
+    private function b64imageOutput($f, $d)
     {
         return $d;
     }
-    function b64imageInput($as, $f, $id, $idfield, $op)
+    private function b64imageInput($as, $f, $id, $idfield, $op)
     {
 
         $new = false;
@@ -2556,7 +2565,7 @@ abstract class GlmDataAbstract
 
         return $b64image;
     }
-    function b64imageStore($in, $f)
+    private function b64imageStore($in, $f)
     {
         return "'".$in."'";
     }
@@ -2564,19 +2573,19 @@ abstract class GlmDataAbstract
     /*
      * File Field Processing
      */
-    function fileField($f)
+    private function fileField($f)
     {
         return 'T.'.$f['field'];
     }
-    function fileOptions($f)
+    private function fileOptions($f)
     {
         return false;
     }
-    function fileOutput($f, $d)
+    private function fileOutput($f, $d)
     {
         return $d;
     }
-    function fileInput($as, $f, $id, $idfield, $op)
+    private function fileInput($as, $f, $id, $idfield, $op)
     {
 
         $new = false;
@@ -2668,7 +2677,7 @@ abstract class GlmDataAbstract
 
         return $current_file;
     }
-    function fileStore($in, $f)
+    private function fileStore($in, $f)
     {
         return "'".addslashes($in)."'";
     }
@@ -2676,15 +2685,15 @@ abstract class GlmDataAbstract
     /*
      * latitude Field Processing
      */
-    function latitudeField($f)
+    private function latitudeField($f)
     {
         return 'T.'.$f['field'];
     }
-    function latitudeOptions($f)
+    private function latitudeOptions($f)
     {
         return false;
     }
-    function latitudeOutput($f, $d)
+    private function latitudeOutput($f, $d)
     {
         $type = 'DMS';
         if (isset($f['latlon_type'])) {
@@ -2700,7 +2709,7 @@ abstract class GlmDataAbstract
 
         return $lat;
     }
-    function latitudeInput($as, $f, $id, $idfield, $op)
+    private function latitudeInput($as, $f, $id, $idfield, $op)
     {
         // If this is setup for a new entry, then just return default value
         if ($op == 'n') {
@@ -2790,7 +2799,7 @@ abstract class GlmDataAbstract
 
         return $in;
     }
-    function latitudeStore($in, $f)
+    private function latitudeStore($in, $f)
     {
         // NOTE: input must be processed first.
 
@@ -2803,15 +2812,15 @@ abstract class GlmDataAbstract
     /*
      * Longitude Field Processing
      */
-    function longitudeField($f)
+    private function longitudeField($f)
     {
         return 'T.'.$f['field'];
     }
-    function longitudeOptions($f)
+    private function longitudeOptions($f)
     {
         return false;
     }
-    function longitudeOutput($f, $d)
+    private function longitudeOutput($f, $d)
     {
 
         $type = 'DMS';
@@ -2828,7 +2837,7 @@ abstract class GlmDataAbstract
 
         return $out;
     }
-    function longitudeInput($as, $f, $id, $idfield, $op)
+    private function longitudeInput($as, $f, $id, $idfield, $op)
     {
         // If this is setup for a new entry, then just return default value
         if ($op == 'n') {
@@ -2918,7 +2927,7 @@ abstract class GlmDataAbstract
 
         return $in;
     }
-    function longitudeStore($in, $f)
+    private function longitudeStore($in, $f)
     {
         // NOTE: input must be processed first.
         // Need to convert to float degrees here
@@ -2937,7 +2946,7 @@ abstract class GlmDataAbstract
      * @return void
      * @access public
      */
-    public function buildFieldsList($op = 'l', $options = false, $defaults = false)
+    private function buildFieldsList($op = 'l', $options = false, $defaults = false)
     {
         $this->fieldData = array();
         $this->select = '';
@@ -3033,7 +3042,7 @@ abstract class GlmDataAbstract
      *
      * @access public
      */
-    public function processOutputData($data, $op = 'l', $forEdit = false, $id = false, $idfield = 'id')
+    private function processOutputData($data, $op = 'l', $forEdit = false, $id = false, $idfield = 'id')
     {
 
         if ($forEdit) {
@@ -3117,7 +3126,7 @@ abstract class GlmDataAbstract
      *
      * @access public
      */
-    public function processInputData($op = 'u', $id = false, $idField = false)
+    private function processInputData($op = 'u', $id = false, $idField = false)
     {
 
         // Status is good unless otherwise determined
@@ -3242,6 +3251,9 @@ abstract class GlmDataAbstract
      *
      * @param string $where Optional WHERE clause for selection of entries. Defaults to all.
      * @param string $order Optional ORDER BY clause for sorting of results.
+     *                      Set to "pseudo-random" for Pseudo-Random sorting that uses a browser cookie
+     *                      to store a custom seed value so all results are in the same randomized order
+     *                      for some period of time. See genPseudoRandIdArray() and pseudoRandDataSort().
      * @param boolean $fieldVals Optional flag requesting fields contain array of all possible values.
      * @param string $idField Optional name of ID field (primary index) to use for result array keys.
      *
@@ -3256,24 +3268,64 @@ abstract class GlmDataAbstract
         // Get field specifications for this instance
         $this->buildFieldsList('l');
 
+        // If pseudo random order is requested
+        $this->pseudoRand = false;
+        if ($order == 'pseudo-random') {
+
+                // Set pseudo random flag and clear the order string
+            $this->pseudoRand = true;
+            $order = '';
+
+        }
+
+        // If doing pseudo-random ordering, generate array of IDs in pseudo-random order
+        $idString = '';
+        if ($this->pseudoRand) {
+
+            $prSql = "SELECT $idField
+                    FROM $this->table T
+            ";
+            if (trim($where) != '') {
+                $prSql .= "WHERE $where
+                ";
+            }
+
+            $idList = $this->wpdb->get_results($prSql, ARRAY_A);
+            $prList = $this->genPseudoRandIdArray($idList, $start, $limit);
+            $idString = $prList['idString'];
+
+        }
+
         $sql = "SELECT $this->select
                 FROM $this->table T
+                WHERE true
         ";
 
         if (trim($where != '')) {
-            $sql .= "WHERE $where
+            $sql .= "AND $where
+            ";
+        }
+
+        // If there's a pseudo-random id list to use for results selection
+        if ($idString != '') {
+            $sql .= "AND T.$idField IN ($idString)
             ";
         }
 
-        if (trim($order != '')) {
+        if (!$this->pseudoRand && trim($order != '')) {
             $sql .= "ORDER BY $order
             ";
         }
 
-        // If $start and $limit, we're doing paging
+        // If $start and $limit, we're doing paging (pseudo-random does it's own paging)
         $paging = false;
         if ($start !== false && $limit > 0) {
-            $sql .= "limit ".($start-1).", $limit";
+
+            // If using pseudo-random, don't use the SQL limit. The pseudo-random code does it's own paging
+            if (!$this->pseudoRand) {
+                $sql .= "limit ".($start-1).", $limit";
+            }
+
             $paging = true;
         }
 
@@ -3295,11 +3347,15 @@ abstract class GlmDataAbstract
             $newList[$v['id']] = $this->processOutputData($v, 'l');
         }
 
+        // If pseudo-random, sort the list by $prList
+        if ($this->pseudoRand) {
+            $this->pseudoRandDataSort($prList, $newList);
+        }
+
         if (is_admin() && GLM_MEMBERS_PLUGIN_ADMIN_DEBUG_VERBOSE && class_exists('glmMembersAdmin')) {
             $this->addDataAbstractNotice($newList, 'DataBlock', "getList() data");
         }
 
-
         // If we're doing paging, return that data along with the list
         if ($paging) {
             $c = count($list);
@@ -3824,7 +3880,7 @@ abstract class GlmDataAbstract
     }
 
     /*
-     * Convert fload degrees to N/S or E/W Lat/Lon as D, D M, or D M S
+     * Convert float degrees to N/S or E/W Lat/Lon as D, D M, or D M S
      *
      * @return array
      *         text        Text output of value
@@ -3833,7 +3889,7 @@ abstract class GlmDataAbstract
      *         min            Minutes
      *        sec            Seconds
      */
-    public function f2LatLon($d, $LatLon, $type, $precision)
+    private function f2LatLon($d, $LatLon, $type, $precision)
     {
 
         $sign = +1;
@@ -3916,7 +3972,7 @@ abstract class GlmDataAbstract
      *
      * @return array
      */
-    public function buildDateFieldLists($min, $max, $time = false)
+    private function buildDateFieldLists($min, $max, $time = false)
     {
 
         if (!$this->optionIncludeSelectListData) {
@@ -3995,7 +4051,7 @@ abstract class GlmDataAbstract
      * @return object Class object
      *
      */
-    public function addDataAbstractNotice ( $d1, $d2 = false, $d3 = false)
+    private function addDataAbstractNotice ( $d1, $d2 = false, $d3 = false)
     {
 
         if (is_admin() && GLM_MEMBERS_PLUGIN_ADMIN_DEBUG_VERBOSE ) {
@@ -4004,5 +4060,174 @@ abstract class GlmDataAbstract
             glmMembersFront::addNotice($d1, $d2, $d3);
         }
     }
+
+    /**
+     * The following two functions are used to build pseudo-random list results with optional paging
+     */
+
+    /*
+     * Generate a list of ID's sorted in pseudo-random order from
+     * a supplied array of record IDs.
+     *
+     * This function checks for a browser cookie that is used to save
+     * the seed. If that seed exists and has not timed out, it is used.
+     * Otherwise a new seed is generated and stored into a browser cookie.
+     *
+     * This function is passed an array of all possible record IDs that have been
+     * retrieved by a query against some table. That query should use a specific
+     * sort order to ensure that the resulting list of IDs is sorted the same
+     * for each identical query.
+     *
+     * Optional start and page size values may be specified to have this function
+     * return a subset of the IDs for a particular page of pagenated results.
+     *
+     * The return from this function is an array of IDs for the desired pseudo-
+     * random results in the desired sequence (numerical keys in sequence).
+     *
+     * Use the PseudoRandArraysort() function to order any selected results that
+     * were generated using the ID list returned from this function.
+     *
+     * @param array $idList       A simple array that's a list of record IDs
+     *                            in the order in which they were retrieved.
+     * @param int $start          Optional start of page value for paging
+     * @param int $length         Optional length of page value for paging
+     *                              (required if there is a $start value)
+     * @param string $idName      Optional id field name to override default 'id'
+     * @param string $cookieName  Optional name for seed cookie
+     * @param int $cookieTime     Optional # of seconds for cookie timeout
+     * @param int $seed Optional seed value to use instead of using value from cookie
+     *
+     * @return array Array inluding the following...
+     *      'idString'      A comma separated string to use for an "in" clause in
+     *                      a second SQL query to get the actual data.
+     *      'idArray'       An array of IDs in the generated pseudo-random order
+     *
+     */
+    private function genPseudoRandIdArray ($ids, $start = false, $length = false, $idName = 'id', $cookieName = 'GLM_PR_SEED', $cookieTime = 86400, $seed = false)
+    {
+
+        $transientSeed = false;     // Indicates if the function was passed a specific seed. These are not stored back into a browser cookie.
+
+        // Change $ids array to simple array of ids
+        foreach ($ids as $k => $v) {
+            $ids[$k] = $v[$idName];
+        }
+
+        // if no id list is supplied
+        if (!is_array($ids) || count($ids) == 0) {
+            return false;
+        }
+
+        // If a seed is supplied
+        if ($seed && is_int($seed)) {
+
+            // Set flag so cookie is not updated with this seed.
+            $transientSeed = true;
+
+        //Otherwise, use a browser cookie seed if available or generate a new one
+        } else {
+
+            // Get browser cookie if it exists
+            if (isset($_COOKIE[$cookieName])) {
+                $seed = ($_COOKIE[$cookieName]);
+            } else {
+
+                // Generate a new seed
+                $seed = intval(time()*1000000+microtime()*1000000);
+
+            }
+        }
+
+        // Enforce seed as positive integer
+        $seed = abs(intval($seed -0));
+
+        // If seed is somehow 0, return false
+        if ($seed == 0) {
+            return false;
+        }
+
+        // If this is not a transient seed, store or updated it into the browser cookie.
+        if (!$transientSeed) {
+            setcookie($cookieName, $seed, time() + $cookieTime);
+        }
+
+        // Use the seed to order the ID list - Note that shuffle() will produce the same results if strand() has the same seed.
+        srand($seed);
+        shuffle($ids);
+
+        // If we have a start value
+        if ($start !== false) {
+
+            // Enforce valid start
+            $start = abs(intval($start-0));
+
+            // Enforce length - Required with a $start value
+            $length = abs(intval($length-0));
+            if ($length == 0) {
+                return false;
+            }
+
+            // Get at max $length elements of the ID array starting with $start
+            $ids = array_slice($ids, $start, $length, true);
+
+
+        }
+
+        // If paging, build comma separated string of id's for use as part of a "in" clause in an SQL query.
+        $idString = '';
+        $newIdArray = array();
+        if ($start !== false) {
+            $sep = '';
+            foreach ($ids as $i) {
+                $idString .= $sep.$i;
+                $sep = ', ';
+            }
+        }
+
+        return array('idString' => $idString, 'idArray' => $ids);
+
+    }
+
+
+    /*
+     * Order a final data array by the sequence of results from genPseudoRandIdArray().
+     *
+     * To use this function...
+     *
+     *  * Query the database to get a list of record IDs only matching the desired result
+     *  * Retrieve an ordered list of those IDs using genPseudoRandIdArray()
+     *  * Query the database again for final results matching the list of IDs
+     *  * Use this function to sort the final resuts by the generated order of IDs
+     *
+     * Note that the $data parameter is used by reference so as to not duplicate the full
+     * data array. This will modify the original array.
+     *
+     * @param array $idArray    An array returned by genPseudoRandIdArray()
+     * @param array &$data      A data array of final results to be ordered
+     * @param string $idName    Optional id field name to override default 'id'
+     *
+     * @return boolean          True if successful, otherwise false
+     *
+     */
+    private function pseudoRandDataSort ($idList, &$data, $idName = 'id')
+    {
+
+        $idFlip = array_flip($idList['idArray']);
+
+        foreach($data as $k=>$v) {
+            $data[$k]['prSort'] = $idFlip[$v[$idName]];
+        }
+
+        uasort( $data, function($a, $b) {
+            if ($a['prSort'] == $b['prSort']) {
+                return 0;
+            }
+            return ($a['prSort'] < $b['prSort']) ? -1 : 1;
+        });
+
+        return true;
+    }
+
+
 }
 ?>
\ No newline at end of file
index b3d3b41..330ff44 100644 (file)
Binary files a/lib/GlmDataAbstract/documentation.odt and b/lib/GlmDataAbstract/documentation.odt differ
index b6aebc7..52cb090 100644 (file)
@@ -525,7 +525,7 @@ class GlmMembersFront_members_list extends GlmDataMemberInfo
             $alphaList = $this->getAlphaList(' AND '.$where, $alphaSelected);
 
         }
-        
+
         /*
          * Check for which view file to use, else default to list
          */
@@ -552,8 +552,9 @@ class GlmMembersFront_members_list extends GlmDataMemberInfo
             // Get stats for the current selection
             $membersFound = $this->getStats(str_replace('T.', '', $where));
 
-            // Get member list and sort
-            $list = $this->getList($where.$alphaWhere, 'member_name');
+            // Get member list and sort - Currently using pseudo-random order
+           //  $list = $this->getList($where.$alphaWhere, 'member_name');
+           $list = $this->getList($where.$alphaWhere, 'pseudo-random');
 
             if (GLM_MEMBERS_PLUGIN_FRONT_DEBUG) {
                 glmMembersFront::addNotice($list, 'DataBlock', 'Member Data');