/** * Returns referenced row. * @param ActiveRow * @param string * @param string|NULL * @return ActiveRow|NULL|FALSE NULL if the row does not exist, FALSE if the relationship does not exist */ public function getReferencedTable(ActiveRow $row, $table, $column = NULL) { if (!$column) { $belongsTo = $this->conventions->getBelongsToReference($this->name, $table); if (!$belongsTo) { return FALSE; } list($table, $column) = $belongsTo; } if (!$row->accessColumn($column)) { return FALSE; } $checkPrimaryKey = $row[$column]; $referenced =& $this->refCache['referenced'][$this->getSpecificCacheKey()]["{$table}.{$column}"]; $selection =& $referenced['selection']; $cacheKeys =& $referenced['cacheKeys']; if ($selection === NULL || $checkPrimaryKey !== NULL && !isset($cacheKeys[$checkPrimaryKey])) { $this->execute(); $cacheKeys = array(); foreach ($this->rows as $row) { if ($row[$column] === NULL) { continue; } $key = $row[$column]; $cacheKeys[$key] = TRUE; } if ($cacheKeys) { $selection = $this->createSelectionInstance($table); $selection->where($selection->getPrimary(), array_keys($cacheKeys)); } else { $selection = array(); } } return isset($selection[$checkPrimaryKey]) ? $selection[$checkPrimaryKey] : NULL; }
/** * Returns referenced row. * @param ActiveRow * @param string * @param string|NULL * @return ActiveRow|NULL|FALSE NULL if the row does not exist, FALSE if the relationship does not exist */ public function getReferencedTable(ActiveRow $row, $table, $column = NULL) { if (!$column) { $belongsTo = $this->conventions->getBelongsToReference($this->name, $table); if (!$belongsTo) { return FALSE; } list($table, $column) = $belongsTo; } if (!$row->accessColumn($column)) { return FALSE; } $checkPrimaryKey = $row[$column]; $referenced =& $this->refCache['referenced'][$this->getSpecificCacheKey()]["{$table}.{$column}"]; $selection =& $referenced['selection']; $cacheKeys =& $referenced['cacheKeys']; if ($selection === NULL || $checkPrimaryKey !== NULL && !isset($cacheKeys[$checkPrimaryKey])) { $this->execute(); $cacheKeys = []; foreach ($this->rows as $row) { if ($row[$column] === NULL) { continue; } $key = $row[$column]; $cacheKeys[$key] = TRUE; } if ($cacheKeys) { $selection = $this->createSelectionInstance($table); //search for foreign key column name which is referenced from activeRow parent table to table from which is selection made $foreign = $this->conventions->getForeign($row->getTable()->getName(), $column); $primary = $foreign == NULL ? $selection->getPrimary() : $foreign; $selection->where($primary, array_keys($cacheKeys)); } else { $selection = NULL; } } return $selection; //return isset($selection[$checkPrimaryKey]) ? $selection[$checkPrimaryKey] : NULL; }
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']}"; }