Exemple #1
0
 /**
  * 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;
 }
Exemple #2
0
    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']}";
    }
Exemple #3
0
    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']}";
    }