1対nのアグリゲーションをマップする
ただしA --* B --* C のように1対nのペアだけで構成される場合のみ。
1対1あるいはn対1はいくらあっても良い。
また、双方向関連はまだ。
class RowSet{ var $data; var $position; var $rowCount; public function __construct($data){ $this->data = $data; $this->position = -1; $this->rowCount = count($data); } public function next(){ $this->position++; if($this->position>= $this->rowCount){ return false; } return true; } public function current(){ return $this->data[$this->position]; } } class EntityMapper{ var $previousRow; var $currentRow; var $rowSet; var $position; var $hasMoreRow; var $metadata; public function __construct($meta,$rowSet){ $this->rowSet = $rowSet; $this->previousRow = array(); $this->currentRow = array(); $this->hasMoreRow = false; $this->metadata = $meta; $this->position = 0; } public function map(){ $this->moveNext(); $entities = array(); $path = $this->newPath(array(),$this->metadata); $keys = array(); while($this->hasMoreRow){ $this->currentRow = $this->rowSet->current(); $entity = $this->mapEntity($this->metadata); $entities[] = $entity; $this->previousRow = $this->currentRow; $seek = $this->mapAssociation($entity,$path,$keys,$this->metadata); if($seek == 0){ $this->moveNext(); } if($this->position> 1000) break;; } return $entities; } function mapAssociation($entity,$path,$keys,$meta){ $this->previousRow = $this->currentRow; $this->position++; if($this->position> 1000) return; $newKeys = $this->newKeys($keys,$meta); $seek = 0; foreach($meta->hasOne as $name => $assoc){ $seek += $this->mapToOne($entity,$path,$newKeys,$assoc); } foreach($meta->belongsTo as $name => $assoc){ $seek += $this->mapToOne($entity,$path,$newKeys,$assoc); } foreach($meta->hasMany as $name => $assoc){ $this->mapToMany($entity,$path,$newKeys,$assoc); $seek++; } return $seek; } function mapToOne($entity,$path,$keys,$meta){ $newEntity = $this->mapEntity($meta); $fieldName = $meta->name; $entity->$fieldName = $newEntity; $newPath = $this->newPath($path,$meta); $seek = $this->mapAssociation($newEntity,$newPath,$keys,$meta); return $seek; } function mapToMany($entity,$path,$keys,$meta){ $fieldName = $meta->name; $entity->$fieldName = array(); $newPath = $this->newPath($path,$meta); while($this->hasMoreRow){ echo "keys :" . implode($keys,",") . "<br />"; $this->position++; if($this->position> 1000) return; if($this->breaks($keys)){ break; } $newEntity = $this->mapEntity($meta); $entity->$fieldName = array_merge($entity->$fieldName,array($newEntity)); $seek = $this->mapAssociation($newEntity,$newPath,$keys,$meta); if($seek == 0){ $this->moveNext(); } } return 1; } function mapEntity($meta){ $entity = new Entity(); foreach($meta->fields as $field){ $columnName = $meta->name . "__" . $field; if(array_key_exists($columnName,$this->currentRow)){ $entity->$field = $this->currentRow[$columnName]; } } return $entity; } function breaks($keys){ $equals = true; foreach($keys as $key){ if(!array_key_exists($key,$this->previousRow)){ $equals = false; break; } if($this->previousRow[$key] == null){ $equals = false; break; } if($this->currentRow[$key] != $this->previousRow[$key]){ echo $this->currentRow[$key]. " : " .$this->previousRow[$key] . " / "; $equals = false; break; } } return !$equals; } function newPath($path,$meta){ $newPath = array_merge($path,array($meta->name)); return $newPath; } function newKeys($keys,$meta){ $newKeys = array(); foreach($meta->primaryKeys as $key){ $newKeys[] = $meta->name. "__" . $key; } $newKeys = array_merge($keys,$newKeys); return $newKeys; } function moveNext(){ $this->hasMoreRow = $this->rowSet->next(); $this->currentRow = $this->rowSet->current(); } } class Entity{ var $rowData; public function __construct(){ $this->rowData = array(); } public function __get($name){ return $this->rowData[$name]; } public function __set($name,$value){ $this->rowData[$name] = $value; } } class Meta{ var $name; var $fields; var $primaryKeys; var $hasMany; var $hasOne; var $belongsTo; public function __construct(){ $this->name = ""; $this->fields = array(); $this->primaryKeys= array(); $this->hasMany = array(); $this->hasOne = array(); $this->belongsTo = array(); } }