2013-08-22

Iterator Modelu w CakePHP

Zadziwiające jak często stajemy przed problemem przeiterowania przez wszystkie rekordy jakiegoś modelu (np. przy generowaniu raportów). Najefektywniejszym rozwiązaniem jest zastosowanie interfejsu iteratora. Uniwersalny przykładem dla CakePHP może być ModelIterator. Klasę umieszczam w katalogu Model/Iterator
 
/**
 * Iterates Model
 *
 * @author gmotyl
 */
class ModelIterator implements Iterator{
  
  protected $key;
  protected $index;
  protected $count;
  protected $conditions;
  protected $Model;

  /**
   * Class constructor
   * 
   * @param array $conditions CakePHP find conditions
   */
  public function __construct($modelName, $conditions = NULL) {
    App::import('Model', $modelName);
    
    $this->Model = new $modelName;
    $this->conditions = $conditions;
    $this->count = $this->Model->find('count', array('conditions' => $conditions));
  }

  /**
   * Returns current row
   * 
   * @return array
   */
  public function current() {
    return $this->Model->find('first', array('conditions' => $this->conditions, 'page' => $this->index));
  }  
  
  /**
   * Increments row
   */
  public function next() {
    $this->index++;
  }
  
  /**
   * Returns index
   * 
   * @return int
   */
  public function key() {
    return $this->index;
  } 
 
  /**
   * Rewind to first index
   */
  public function rewind() {
    $this->index = 1;
  }
  
  /**
   * Returns FALSE if iteration is over
   */
  public function valid() {
    return ($this->count >= $this->index);
  }
}
Dodatkowo wygodnie będzie zaimplementować interfejs IteratorAggregate w AppModel (po którym dziedziczą wszystkie Modele w CakePHP:


App::uses('ModelIterator', 'Model/Iterator');

class AppModel extends Model implements IteratorAggregate{

(...)

  public function getIterator() {
    return new ModelIterator($this->name);
  }

(...)
Dzięki temu możemy w dowolnym miejscu użyć kostrukcji foreach, która przeiteruje się przez wszystkie elementy Modelu bez konieczności jawnego instancjonowania iteratora np. w kontrolerze UsersController :


    foreach ($this->User as $user) {
      debug($user);
    }   

Brak komentarzy:

Prześlij komentarz