/** * Returns referencing rows. * @param string * @param string * @param int primary key * @return GroupedSelection */ public function getReferencingTable($table, $column, $active = NULL) { if (strpos($table, '.') !== FALSE) { list($table, $column) = explode('.', $table); } elseif (!$column) { $hasMany = $this->conventions->getHasManyReference($this->name, $table); if (!$hasMany) { return FALSE; } list($table, $column) = $hasMany; } $prototype =& $this->refCache['referencingPrototype'][$this->getSpecificCacheKey()]["{$table}.{$column}"]; if (!$prototype) { $prototype = $this->createGroupedSelectionInstance($table, $column); $prototype->where("{$table}.{$column}", array_keys((array) $this->rows)); } $clone = clone $prototype; $clone->setActive($active); return $clone; }
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']}"; }