PHP Classes

File: multiRecordsetItorator.php

Recommend this page to a friend!
  Classes of Matthew Daniel   Multiple PHP PDOStatement Iterator   multiRecordsetItorator.php   Download  
File: multiRecordsetItorator.php
Role: Class source
Content type: text/plain
Description: Main class
Class: Multiple PHP PDOStatement Iterator
Iterate over multiple query results using PDO
Author: By
Last change: forgot to add the extension to the file name
Date: 11 years ago
Size: 5,676 bytes
 

Contents

Class file image Download
<?php

// multiRecordsetItorator class
//
// This is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See <http://www.gnu.org/licenses/>.

class multiPDOStatementIterator implements Iterator {
   
/*
     * Holds all the passed in recordset
     */
   
protected $pdostatements;

   
/*
     * Database field that all recordsets are ordered by and contain.
     */
   
protected $keyfield;

   
/*
     * This is an incrementor so that we have a unique key in the loop
     */
   
protected $externalkey = 0;

   
/*
     * This is the set we are looking (eg. userid)
     */
   
protected $internalkey;

   
/*
     * So that we know where we are
     */
   
protected $currentcache;

   
/*
     * So that we know where we have been
     */
   
protected $previouscache;

   
/*
     * cache the order
     */
   
protected $order;

    const
ASC = 'asc';
    const
DESC = 'desc';

   
/**
     * Allows you to iterate over ordered recordsets by the keyfield that is passed.
     *
     * If you have a multiple sets of data and they all have a user field you can use this
     * to loop over them starting with the elements in the first recordset that match the key
     * and moving on to the elements in each passed set.
     *
     * @param string $keyfield
     * @param PDOStatement $var [,PDOStatement $...]
     */
   
public function __construct($keyfield, $sortorder=self::ASC) {
       
$this->pdostatements = func_get_args();

       
$this->keyfield = array_shift($this->pdostatements);
       
$this->order = array_shift($this->pdostatements);

       
// populate the first cache
       
$this->latestRecordCache = array_map(function ($recordset) {
            return
$recordset->fetchObject();
        },
$this->pdostatements);

       
$this->setInternalKeyToNext();

       
$this->setCurrentToNextForInternalKey();
    }
 
   public function
valid() {
      
// is there at least one recordset that still has unsent records?
      
$key = $this->keyfield; // php < 5.4 doesn't have access to $this in array_reduce
      
return array_reduce($this->latestRecordCache, function ($nonemptyrecordset, $currentRecord) use ($key) {
           return
$nonemptyrecordset || !empty($currentRecord->$key) ? true : false;
       });
    }

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

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

    public function
previous() {
        return
$this->previouscache;
    }

    public function
next() {
        if (!
$this->valid()) {
            return
false;
        }

       
// First try to return anything with the current internal key and move the cache to next record
       
if ($this->setCurrentToNextForInternalKey() !== false) {
           
$this->externalkey++;
            return
$this->currentcache;
        }

       
// nothing with the current internal key so we need to move on to next set
       
$this->setInternalKeyToNext();

       
// since we've moved the internal key then recursively call in to get the next record
       
return $this->next();
    }

    public function
rewind() {
       
// can only rewind this the first time
       
if (!empty($this->externalkey)) {
            throw new
Exception('Cannot rewind more than once.');
        }
    }

   
/**
     * Get the next record from the various recordset that belongs to the current key
     *
     * @return boolean true if record found else false
     */
   
protected function setCurrentToNextForInternalKey() {
        foreach (
$this->latestRecordCache as $recordsetkey => $record) {
           
$recordkeyval = !empty($record->{$this->keyfield}) ? $record->{$this->keyfield} : false;

            if (!empty(
$recordkeyval) && $recordkeyval == $this->internalkey) {
               
$nextrecord = $this->pdostatements[$recordsetkey]->fetchObject();

               
$this->previouscache = $this->currentcache;
               
$this->currentcache = $nextrecord;

               
$this->latestRecordCache[$recordsetkey] = $nextrecord;

                return
$nextrecord != false;
            }
        }

        return
false;
    }

   
/**
     * Set the internal pointer to the lowest keyfield id of the recordsets.
     *
     * This is necessary so we know which set of records we are on
     *
     */
   
protected function setInternalKeyToNext() {
       
$this->internalkey = array_reduce($this->latestRecordCache, function ($nextSmallest, $record) {
           
$recordkeyval = !empty($record->{$this->keyfield}) ? $record->{$this->keyfield} : false;

            if (empty(
$nextSmallest) && !empty($recordkeyval)) {
                return
$recordkeyval;
            }

            if (!empty(
$recordkeyval)) {
                if (
$this->order == self::ASC && $recordkeyval < $nextSmallest) {
                    return
$recordkeyval;
                } elseif (
$this->order == self::DESC && $recordkeyval > $nextSmallest) {
                    return
$recordkeyval;
                }
            }
           
            return
$nextSmallest;
        });
    }
}