UserSearch.php 6.47 KB
<?php
namespace Tz\WordPress\Tools;
use ArrayAccess, Iterator, Countable;

/*
    Get all active CBV users who are subscribers

    $users = new UserSearch(
        Array('first_name', 'last_name')
      , -1
      , 1
      , 'last_name'
      , 'ASC'
      , Array('status' => 'active')
      , null
      , Array(16)
    );
    $user->setUserClass('Tz\WordPress\CBV\User\Account');

    // Each $user is an Account (extension of) Tools\User (extension of) WP_User object
    foreach ($users as $i => $user) {
        echo "{$user->first_name} {$user->last_name} ($user->getRole()}";
    }

    // Note, although the example is tailored for CBV, this will work with all WordPress installs
*/

class UserSearch implements ArrayAccess, Iterator, Countable {
    protected $result;
    protected $pos      = 0;

    protected $count    = 0;
    protected $num_rows = 0;

    protected $fields   = Array();

    protected $userclass = 'User';

    public function __construct(Array $fields, $num_results = -1, $page = 1, $sortby = null, $sortorder = 'ASC', Array $field_match = null, $text_search = null, Array $in_groups = null) {
        $this->userclass = __NAMESPACE__ . '\User';

        global $wpdb;

        $this->fields  = $fields;
        $search_clause = $limit_clause = $order_clause = $order_sort = $having_clause = $uam_join = $uam_clause = '';

        // Field matches
        $having = " HAVING `json` LIKE ";
        if (is_array($field_match) && count($field_match) > 0) {
            foreach ($field_match as $key => $val) {
                if (!in_array($key, $this->fields)) {
                    $this->fields[] = $key;
                }

                $having_clause .= (empty($having_clause) ? $having : "\n AND `json` LIKE ");
                $having_clause .= " '%\"{$key}\":\"{$val}%' ";
            }
        }

        // Open ended search
        if (!is_null($text_search)) {
            $search_strings = explode(' ', $text_search);

            foreach ($search_strings as $search) {
                $having_clause .= (empty($having_clause) ? $having : "\n AND `json` LIKE ");
                $having_clause .= " '%{$search}%' ";
            }
        }

        // Order
        if (!is_null($sortby)) {
            $order_clause = " , GROUP_CONCAT(IF(`meta_key` = '{$sortby}', `meta_value`, '') SEPARATOR '') AS `fake_order` ";
            $order_sort   = " ORDER BY `fake_order` " . ($sortorder == 'DESC' ? 'DESC' : 'ASC');
        }

        // Pagination
        if ($num_results > 0) {    
            $limit_clause = " LIMIT " . (($page - 1) * $num_results ) . ", {$num_results}";
        }

        // Groups
        if (is_array($in_groups) && count($in_groups) > 0 && is_plugin_active('tz-user-access-manager/user-access-manager.php')) {
            $uam_join   = " LEFT JOIN `wp_uam_accessgroup_to_object` AS `uam` ON `wp_usermeta`.`user_id` = `uam`.`object_id` ";
            $uam_clause = " AND `uam`.`object_type` = 'user' AND `uam`.`group_id` IN (" . implode(',', $in_groups) . ") ";
        }

        mysql_query("SET SESSION group_concat_max_len = 40960", $wpdb->dbh);

        $query = "
          SELECT SQL_CALC_FOUND_ROWS 
                 `user_id`
               , CONCAT(
                     '{'
                   , GROUP_CONCAT(
                         '\"'
                       , `meta_key`
                       , '\":\"'
                       , REPLACE(REPLACE(REPLACE(`meta_value`, '" . '"' . "', '" . '\\\"' . "'), '\\r', '\\\\r'), '\\n', '\\\\n')
                       , '\"'
                     )
                   , '}'
                 ) AS `json`
               {$order_clause}
            FROM `wp_usermeta`
                 {$uam_join}
           WHERE 
                 `meta_key` IN ('" . implode("','", $this->fields) . "')
                 {$uam_clause}
        GROUP BY `user_id`
                 {$having_clause}
                 {$order_sort}
                 {$limit_clause}
        ";
/*
?>
<textarea style="width: 95%; height: 35em; font-size: 11px;" autofocus="autofocus">
    <?php echo trim($query); ?>;
</textarea>
<?php
/**/
        $this->result   = mysql_query($query, $wpdb->dbh);
        $this->num_rows = mysql_num_rows($this->result);

        $count_result = mysql_query("SELECT FOUND_ROWS()", $wpdb->dbh);
        list($this->count) = mysql_fetch_row($count_result);
    }

    public function setUserClass($classname) {
        $this->userclass = $classname;
    }

    public function countTotal() {
        return $this->count;
    }

    public function count() {
        return $this->num_rows;
    }

    public function current() {
        return $this->offsetGet($this->pos);
    }

    public function key() {
        return $this->pos;
    }

    public function next() {
        $this->pos++;
    }

    public function rewind() {
        $this->current = 0;

        if ($this->num_rows > 0) {
            mysql_data_seek($this->result, 0);
        }
    }

    public function valid() {
        return $this->offsetExists($this->pos);
    }

    public function offsetExists($offset) {
        if ($this->num_rows == 0) {
            return false;
        }

        return ($offset < 0 || $offset > ($this->num_rows - 1) ? false : true);
    }

    public function offsetGet($offset) {
        if (!$this->offsetExists($offset)) {
            return false;
        }

        if ($offset != $this->pos) {
            mysql_data_seek($this->result, $offset);
        }

        list($user_id, $user_string) = mysql_fetch_row($this->result);
        $json_data = json_decode($user_string, true);
        if (json_last_error() != JSON_ERROR_NONE) {
            return false;
        }
        $data = array_merge(array_map(function() { return ''; }, array_flip($this->fields)), $json_data);
        foreach ($data as $key => &$val) {
            $val = maybe_unserialize($val);
        }

        return unserialize(sprintf(
            'O:%5$d:"%4$s":3:{s:10:"_metacache";%3$ss:2:"id";s:%2$d:"%1$d";s:2:"ID";s:%2$d:"%1$d";}'
          , $user_id
          , strlen($user_id)
          , serialize($data)
          , $this->userclass
          , strlen($this->userclass)
        ));
    }

    public function offsetSet($offset, $value) {
        throw new Exception("You're...you're crazy man.  I like you, but you're crazy.");
    }

    public function offsetUnset($offset) {
        throw new Exception("You're...you're crazy man.  I like you, but you're crazy.");
    }
}
/*

class UserInjector extends Pimple {
    public function __construct(Array $config = null) {
        $this += $config;
    }
}
*/