connection = $connection; $this->db = $connection->getDbAdapter(); return $this; } /** * Prepare the query and fetch all data * * @return array */ public function fetchAll() { $query = $this->fullQuery(); return $this->db()->fetchAll($query); } /** * Choose a one or more facts * * This also initializes a fact column lookup array * * @param array $facts * @return $this */ public function chooseFacts(array $facts) { parent::chooseFacts($facts); $this->factColumns = array(); $columns = $this->getAvailableFactColumns(); foreach ($this->chosenFacts as $name) { $this->factColumns[$name] = $columns[$name]; } return $this; } /** * @param $name * @return $this */ public function setDbName($name) { $this->dbName = $name; return $this; } /** * Gives back the table name, eventually prefixed with a defined DB name * * @param string $name * @return string */ public function tableName($name) { if ($this->dbName === null) { return $name; } else { return $this->dbName . '.' . $name; } } /** * Returns an eventually defined DB name * * @return string|null */ public function getDbName() { return $this->dbName; } /** * Get our inner query * * Hint: mostly used to get rid of NULL values * * @return ZfSelectWrapper */ public function innerQuery() { if ($this->innerQuery === null) { $this->innerQuery = new ZfSelectWrapper($this->prepareInnerQuery()); } return $this->innerQuery; } /** * We first prepare the queries and to finalize it later on * * This way dimensions can be added one by one, they will be allowed to * optionally join additional tables or apply other modifications late * in the process * * @return void */ public function finalizeInnerQuery() { $query = $this->innerQuery()->unwrap(); $columns = array(); foreach ($this->dimensions as $name => $dimension) { $dimension->addToCube($this); if ($this->hasSlice($name)) { $query->where( $dimension->getColumnExpression($this) . ' = ?', $this->slices[$name] ); } else { $columns[$name] = $dimension->getColumnExpression($this); } } $c = []; foreach ($columns + $this->factColumns as $k => $v) { $c[$this->db()->quoteIdentifier([$k])] = $v; } $query->columns($c); } /** * Lazy-load our full query * * @return \Zend_Db_Select */ protected function fullQuery() { if ($this->fullQuery === null) { $this->fullQuery = $this->prepareFullQuery(); } return $this->fullQuery; } /** * Lazy-load our full query * * @return \Zend_Db_Select */ protected function rollupQuery() { if ($this->rollupQuery === null) { $this->rollupQuery = $this->prepareRollupQuery(); } return $this->rollupQuery; } /** * The full query wraps the rollup query in a sub-query to work around * MySQL limitations. This is required to not get into trouble when ordering, * especially combined with the need to keep control over (eventually desired) * NULL value fact columns * * @return \Zend_Db_Select */ protected function prepareFullQuery() { $alias = 'rollup'; $cols = $this->listColumns(); $columns = array(); foreach ($cols as $col) { $columns[$this->db()->quoteIdentifier([$col])] = $alias . '.' . $this->db()->quoteIdentifier([$col]); } $select = $this->db()->select()->from( array($alias => $this->rollupQuery()), $columns ); foreach ($columns as $col) { $select->order('(' . $col . ' IS NOT NULL)'); $select->order($col); } return $select; } /** * Provide access to our DB * * @return \Zend_Db_Adapter_Abstract */ public function db() { return $this->db; } /** * Whether our connection is PostgreSQL * * @return bool */ public function isPgsql() { return $this->connection->getDbType() === 'pgsql'; } /** * This prepares the rollup query * * Inner query is wrapped in a subquery, summaries for all facts are * fetched. Rollup considers all defined dimensions and expects them * to exist as columns in the innerQuery * * @return \Zend_Db_Select */ protected function prepareRollupQuery() { $alias = 'sub'; $dimensions = array_map(function ($val) { return $this->db()->quoteIdentifier([$val]); }, array_keys($this->listDimensions())); $this->finalizeInnerQuery(); $columns = array(); foreach ($dimensions as $dimension) { $columns[$dimension] = $alias . '.' . $dimension; } foreach ($this->listFacts() as $fact) { $columns[$fact] = 'SUM(' . $fact . ')'; } $select = $this->db()->select()->from( array($alias => $this->innerQuery()->unwrap()), $columns ); if ($this->isPgsql()) { $select->group('ROLLUP (' . implode(', ', $dimensions) . ')'); } else { $select->group('(' . implode('), (', $dimensions) . ') WITH ROLLUP'); } return $select; } }