/** * Creates filtered table representation. * @param Context * @param IConventions * @param string table name * @param Nette\Caching\IStorage|NULL */ public function __construct(Context $context, IConventions $conventions, $tableName, Nette\Caching\IStorage $cacheStorage = NULL) { $this->context = $context; $this->conventions = $conventions; $this->name = $tableName; $this->cache = $cacheStorage ? new Nette\Caching\Cache($cacheStorage, 'Nette.Database.' . md5($context->getConnection()->getDsn())) : NULL; $this->primary = $conventions->getPrimary($tableName); $this->sqlBuilder = new SqlBuilder($tableName, $context); $this->refCache =& $this->getRefTable($refPath)->globalRefCache[$refPath]; }
public function parseJoinsCb(&$joins, $match) { $chain = $match['chain']; if (!empty($chain[0]) && ($chain[0] !== '.' && $chain[0] !== ':')) { $chain = '.' . $chain; // unified chain format } preg_match_all('~ (?(DEFINE) (?P<word> [\\w_]*[a-z][\\w_]* ) ) (?P<del> [.:])?(?P<key> (?&word))(\\((?P<throughColumn> (?&word))\\))? ~xi', $chain, $keyMatches, PREG_SET_ORDER); $parent = $this->tableName; $parentAlias = preg_replace('#^(.*\\.)?(.*)$#', '$2', $this->tableName); // join schema keyMatch and table keyMatch to schema.table keyMatch if ($this->driver->isSupported(ISupplementalDriver::SUPPORT_SCHEMA) && count($keyMatches) > 1) { $tables = $this->getCachedTableList(); if (!isset($tables[$keyMatches[0]['key']]) && isset($tables[$keyMatches[0]['key'] . '.' . $keyMatches[1]['key']])) { $keyMatch = array_shift($keyMatches); $keyMatches[0]['key'] = $keyMatch['key'] . '.' . $keyMatches[0]['key']; $keyMatches[0]['del'] = $keyMatch['del']; } } // do not make a join when referencing to the current table column - inner conditions // check it only when not making backjoin on itself - outer condition if ($keyMatches[0]['del'] === '.') { if ($parent === $keyMatches[0]['key']) { return "{$parent}.{$match['column']}"; } elseif ($parentAlias === $keyMatches[0]['key']) { return "{$parentAlias}.{$match['column']}"; } } foreach ($keyMatches as $keyMatch) { if ($keyMatch['del'] === ':') { if (isset($keyMatch['throughColumn'])) { $table = $keyMatch['key']; $belongsTo = $this->conventions->getBelongsToReference($table, $keyMatch['throughColumn']); if (!$belongsTo) { throw new Nette\InvalidArgumentException("No reference found for \${$parent}->{$keyMatch['key']}."); } list(, $primary) = $belongsTo; } else { $hasMany = $this->conventions->getHasManyReference($parent, $keyMatch['key']); if (!$hasMany) { throw new Nette\InvalidArgumentException("No reference found for \${$parent}->related({$keyMatch['key']})."); } list($table, $primary) = $hasMany; } $column = $this->conventions->getPrimary($parent); } else { $belongsTo = $this->conventions->getBelongsToReference($parent, $keyMatch['key']); if (!$belongsTo) { throw new Nette\InvalidArgumentException("No reference found for \${$parent}->{$keyMatch['key']}."); } list($table, $column) = $belongsTo; $primary = $this->conventions->getPrimary($table); } $tableAlias = $keyMatch['key'] ?: preg_replace('#^(.*\\.)?(.*)$#', '$2', $table); // if we are joining itself (parent table), we must alias joining table if ($parent === $table) { $tableAlias = $parentAlias . '_ref'; } $joins[$tableAlias . $column] = [$table, $tableAlias, $parentAlias, $column, $primary]; $parent = $table; $parentAlias = $tableAlias; } return $tableAlias . ".{$match['column']}"; }
public function parseJoinsCb(&$joins, $match) { $chain = $match['chain']; if (!empty($chain[0]) && ($chain[0] !== '.' && $chain[0] !== ':')) { $chain = '.' . $chain; // unified chain format } preg_match_all('~ (?(DEFINE) (?P<word> [\\w_]*[a-z][\\w_]* ) ) (?P<del> [.:])?(?P<key> (?&word))(\\((?P<throughColumn> (?&word))\\))? ~xi', $chain, $keyMatches, PREG_SET_ORDER); $parent = $this->tableName; $parentAlias = preg_replace('#^(.*\\.)?(.*)$#', '$2', $this->tableName); // join schema keyMatch and table keyMatch to schema.table keyMatch if ($this->driver->isSupported(ISupplementalDriver::SUPPORT_SCHEMA) && count($keyMatches) > 1) { $tables = $this->getCachedTableList(); if (!isset($tables[$keyMatches[0]['key']]) && isset($tables[$keyMatches[0]['key'] . '.' . $keyMatches[1]['key']])) { $keyMatch = array_shift($keyMatches); $keyMatches[0]['key'] = $keyMatch['key'] . '.' . $keyMatches[0]['key']; $keyMatches[0]['del'] = $keyMatch['del']; } } // do not make a join when referencing to the current table column - inner conditions // check it only when not making backjoin on itself - outer condition if ($keyMatches[0]['del'] === '.') { if (count($keyMatches) > 1 && ($parent === $keyMatches[0]['key'] || $parentAlias === $keyMatches[0]['key'])) { throw new Nette\InvalidArgumentException("Do not prefix table chain with origin table name '{$keyMatches[0]['key']}'. If you want to make self reference, please add alias."); } if ($parent === $keyMatches[0]['key']) { return "{$parent}.{$match['column']}"; } elseif ($parentAlias === $keyMatches[0]['key']) { return "{$parentAlias}.{$match['column']}"; } } $tableChain = NULL; foreach ($keyMatches as $index => $keyMatch) { $isLast = !isset($keyMatches[$index + 1]); if (!$index && isset($this->aliases[$keyMatch['key']])) { if ($keyMatch['del'] === ':') { throw new Nette\InvalidArgumentException("You are using has many syntax with alias (':{$keyMatch['key']}'). You have to move it to alias definition."); } else { $previousAlias = $this->currentAlias; $this->currentAlias = $keyMatch['key']; $requiredJoins = []; $query = $this->aliases[$keyMatch['key']] . '.foo'; $this->parseJoins($requiredJoins, $query); $aliasJoin = array_pop($requiredJoins); $joins += $requiredJoins; list($table, , $parentAlias, $column, $primary) = $aliasJoin; $this->currentAlias = $previousAlias; } } elseif ($keyMatch['del'] === ':') { if (isset($keyMatch['throughColumn'])) { $table = $keyMatch['key']; $belongsTo = $this->conventions->getBelongsToReference($table, $keyMatch['throughColumn']); if (!$belongsTo) { throw new Nette\InvalidArgumentException("No reference found for \${$parent}->{$keyMatch['key']}."); } list(, $primary) = $belongsTo; } else { $hasMany = $this->conventions->getHasManyReference($parent, $keyMatch['key']); if (!$hasMany) { throw new Nette\InvalidArgumentException("No reference found for \${$parent}->related({$keyMatch['key']})."); } list($table, $primary) = $hasMany; } $column = $this->conventions->getPrimary($parent); } else { $belongsTo = $this->conventions->getBelongsToReference($parent, $keyMatch['key']); if (!$belongsTo) { throw new Nette\InvalidArgumentException("No reference found for \${$parent}->{$keyMatch['key']}."); } list($table, $column) = $belongsTo; $primary = $this->conventions->getPrimary($table); } if ($this->currentAlias && $isLast) { $tableAlias = $this->currentAlias; } elseif ($parent === $table) { $tableAlias = $parentAlias . '_ref'; } elseif ($keyMatch['key']) { $tableAlias = $keyMatch['key']; } else { $tableAlias = preg_replace('#^(.*\\.)?(.*)$#', '$2', $table); } $tableChain .= $keyMatch[0]; if (!$isLast || !$this->currentAlias) { $this->checkUniqueTableName($tableAlias, $tableChain); } $joins[$tableAlias] = [$table, $tableAlias, $parentAlias, $column, $primary]; $parent = $table; $parentAlias = $tableAlias; } return $tableAlias . ".{$match['column']}"; }