/** * Select * * @param string $expression Expression which creates a resulting element * @return mixed */ public function select($expression = null) { // Return value $returnValue = array(); // Zend_Db_Select expression $zendDbSelect = null; // Expression set? if (is_null($expression) || $expression == '') { $expression = $this->_from . ' => ' . $this->_from; } // Data source $dataSourceInfo = $this->_data->info(); $dataSource = $this->_data->select()->from(array($this->_from => $dataSourceInfo['name']), $this->_columns); // Create selector expression $selector = new PHPLinq_Expression($expression, $this->_from); // Build Zend_Db_Select chain $zendDbSelect = $dataSource; // Distinct set? if (!is_null($this->_distinct)) { $zendDbSelect = $zendDbSelect->distinct(); } // Join set? if (count($this->_childProviders) > 0) { // Check if the child providers can be supported foreach ($this->_childProviders as $provider) { if (get_class($provider) != __CLASS__) { throw new PHPLinq_Exception('Joins of ' . get_class($provider) . ' on ' . __CLASS__ . ' are not supported.'); } else { // Supported! Add join $joinInfo = $provider->getSource()->info(); $dataSource = $dataSource->join(array($provider->getFromName() => $joinInfo['name']), $this->_convertToSql($provider->getJoinCondition()->getFunction()->getFunctionCode())); } } } // Where expresion set? Evaluate it! if (!is_null($this->_where)) { $functionCode = $this->_convertToSql($this->_where->getFunction()->getFunctionCode(), $dataSource->getAdapter()->getQuoteIdentifierSymbol()); $zendDbSelect = $zendDbSelect->where($functionCode); } // OrderBy set? if (is_array($this->_orderBy) && count($this->_orderBy) > 0) { $orderBy = array(); foreach ($this->_orderBy as $orderByExpression) { $orderBy[] = new Zend_Db_Expr($this->_convertToSql($orderByExpression->getExpression()->getFunction()->getFunctionCode()) . ($orderByExpression->isDescending() ? ' DESC' : ' ASC')); } $zendDbSelect = $zendDbSelect->order($orderBy); } // Take / skip $zendDbSelect->limit($this->_take, $this->_skip); // No integrity check needed, joins can be free format $zendDbSelect->setIntegrityCheck(false); // Log query string if (!is_null(self::$_queryCallback)) { if (!is_array(self::$_queryCallback) && in_array(self::$_queryCallback, self::$_internalFunctions)) { self::$_queryCallback = create_function('$query', self::$_queryCallback . '($query);'); } call_user_func(self::$_queryCallback, $zendDbSelect->__toString()); } // Query $results = null; if (count($this->_childProviders) == 0) { // No join, easy! $results = $zendDbSelect->query(Zend_Db::FETCH_OBJ)->fetchAll(); // Row class set? If so, convert all data! if ($this->_data->getRowClass() != 'Zend_Db_Table_Row') { $rowClass = $this->_data->getRowClass(); $tempResults = array(); foreach ($results as $result) { $tempResult = call_user_func(array($rowClass, 'fromArray'), (array) $result); $tempResults[] = $tempResult; } $results = $tempResults; } } else { // Get data in mode FETCH_NAMED $tempResults = $zendDbSelect->query(Zend_Db::FETCH_NAMED)->fetchAll(); // Fetch info $info = array($this->_data->info()); foreach ($this->_childProviders as $provider) { $info[] = $provider->getSource()->info(); } // Build proper resultset $results = array(); $currentResult = null; $currentObject = null; foreach ($tempResults as $tempResult) { $currentResult = array(); // For each table, add a new object with values for ($i = 0; $i < count($info); $i++) { // Fill object data $currentObject = array(); foreach ($info[$i]['cols'] as $column) { if (!is_array($tempResult[$column])) { // Regular column $currentObject[$column] = $tempResult[$column]; } else { // Some searching to do... for ($j = $i; $j >= 0; $j--) { if (isset($tempResult[$column][$j])) { $currentObject[$column] = $tempResult[$column][$j]; $j = -1; } } } } // Add object to result table. // Row class set? If so, convert all data! if ($i == 0 && $this->_data->getRowClass() != 'Zend_Db_Table_Row' || $this->_childProviders[$i - 1]->getSource()->getRowClass() != 'Zend_Db_Table_Row') { $rowClass = $i == 0 ? $this->_data->getRowClass() : $this->_childProviders[$i - 1]->getSource()->getRowClass(); $currentResult[] = call_user_func(array($rowClass, 'fromArray'), (array) $currentObject); } else { $currentResult[] = (object) $currentObject; } } $results[] = $currentResult; } } // Loop trough data source foreach ($results as $value) { // Is it a valid element? $isValid = true; // OfType expresion set? Evaluate it! if ($isValid && !is_null($this->_ofType)) { $isValid = $this->_ofType->execute($value); } // The element is valid, check if it is our selection range if ($isValid) { // Skip element? if (!is_null($this->_skipWhile) && $this->_skipWhile->execute($value)) { $isValid = false; } // Take element? if (!is_null($this->_takeWhile) && !$this->_takeWhile->execute($value)) { $isValid = false; break; } // Add the element to the return value if it is a valid element if ($isValid) { $returnValue[] = $selector->execute($value); } } } // TODO: // - join // - aggregates // - translate more SQL! // Return value return $returnValue; }