Login   Register  
PHP Classes
elePHPant
Icontem

File: multiRecordsetItorator.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  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: 2013-03-17 13:32
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;
        });
    }
}