/** * Fetch a single result of this query. Builds a Model object if the $parse_objects flag is set. This will * also attach any joined or with objects to their associated targets. * * @param bool $parse_objects If true the array is filled with Model objects, otherwise the result is an array * of associative arrays. * @param bool $debug Used to print the query to STDOUT before being executed * * @return Model|array|null */ public function fetchRow($parse_objects = true, $debug = false) { $object_instances = array(); if (!$this->_executed) { $this->execute($debug); } for (;;) { if ($this->_last_row === false) { $this->_last_row = $this->_statement->fetch(); } //if still false, return null (no rows left in set) if ($this->_last_row === false) { break; } //if not bothering to parse object if (!$parse_objects) { $output = array(); // if it's a manual select (fields were manually specified) then just put the // requested fields into the output directly, keyed by their aliases. if ($this->manual_select) { if (isset($this->fields[0])) { throw new Exception('An associative array must be passed in to \\Wave\\DB\\Query::from() when not parsing objects'); } foreach ($this->fields as $alias => $field) { if (isset($this->_last_row[$alias])) { $key = $this->manual_select ? $alias : $field; $output[$key] = $this->_last_row[$alias]; } } } else { foreach ($this->class_aliases[$this->from_alias]['columns'] as $column => $column_alias) { $output[$column] = $this->_last_row[$column_alias]; } foreach ($this->class_aliases as $alias => $class_details) { if ($alias === $this->from_alias) { continue; } foreach ($class_details['columns'] as $column => $column_alias) { $output[$alias][$column] = $this->_last_row[$column_alias]; } } } $this->_last_row = false; return $output; } //if there's no instance of the main class, create a new one. if (!isset($object_instances[$this->from_alias])) { $object_instances[$this->from_alias] = $this->buildClassInstance($this->from_alias); } if ($object_instances[$this->from_alias] === null) { trigger_error('Insufficient data in SELECT to build object instance.'); return null; } //if there are joins, check that the current row still has the same $from_instance, if it doesn't, break. //otherwise build the related objects and put them on it. if (isset($this->joins[0])) { //if the from instance is different, break and leave it for the next call to fetchRow(). foreach ($object_instances[$this->from_alias]->_getIdentifyingData() as $property => $value) { $class = $this->class_aliases[$this->from_alias]['class']; $alias = $this->class_aliases[$this->from_alias]['columns'][$property]; $cast_value = $this->database->valueFromSQL($this->_last_row[$alias], $class::_getField($property)); if ($cast_value !== $value) { return isset($object_instances[$this->from_alias]) ? $object_instances[$this->from_alias] : null; } // break 2; } //otherwise build the child rows foreach ($this->joins as $join) { $object_instances[$join['table_alias']] = $this->buildClassInstance($join['table_alias']); } //then check non-null child rows and add them to their parent rows foreach ($this->joins as $join) { if ($object_instances[$join['table_alias']] === null) { continue; } //find if is a join or a with if (isset($this->with[$join['table_alias']])) { switch ($this->with[$join['table_alias']]['relation_type']) { case Wave\DB\Relation::ONE_TO_ONE: case Wave\DB\Relation::MANY_TO_ONE: $object_instances[$join['target_alias']]->{'set' . $this->with[$join['table_alias']]['relation_name']}($object_instances[$join['table_alias']], false); break; case Wave\DB\Relation::ONE_TO_MANY: case Wave\DB\Relation::MANY_TO_MANY: $object_instances[$join['target_alias']]->{'add' . $this->with[$join['table_alias']]['relation_name']}($object_instances[$join['table_alias']], false); break; } } else { $object_instances[$join['target_alias']]->addJoinedObject($object_instances[$join['table_alias']], $join['table_alias'], $this->unaliasClass($join['table_alias'])); } } //set the _last_row to false as it has been processed and this will force the next call to get another one. $this->_last_row = false; } else { //if no joins, just break from loop and return the $from_instance. break; } } // reset the last row pointer since we've finished with this row now. $this->_last_row = false; return isset($object_instances[$this->from_alias]) ? $object_instances[$this->from_alias] : null; }