Adds a foreignkey to this table.

@param relationName  The name of the relation represented by the foreignkey
@param remoteTable   The referenced table
@param localColumns  The local columns
@param remoteColumns The remote columns
518698
public void addForeignkey(String relationName, String remoteTable, List localColumns, List remoteColumns)
    {
        ForeignkeyDef foreignkeyDef = new ForeignkeyDef(relationName, remoteTable);

        // the field arrays have the same length if we already checked the constraints
        for (int idx = 0; idx < localColumns.size(); idx++)
        {
            foreignkeyDef.addColumnPair((String)localColumns.get(idx),
                                        (String)remoteColumns.get(idx));
        }

        // we got to determine whether this foreignkey is already present 
        ForeignkeyDef def = null;

        for (Iterator it = getForeignkeys(); it.hasNext();)
        {
            def = (ForeignkeyDef)it.next();
            if (foreignkeyDef.equals(def))
            {
                return;
            }
        }
        foreignkeyDef.setOwner(this);
        _foreignkeys.add(foreignkeyDef);
    }
244963
public static PreparedStatement createRelationMemberTable(Connection connection, String relationMemberTable) throws SQLException {
        try (Statement stmt = connection.createStatement()) {
            StringBuilder sb = new StringBuilder("CREATE TABLE ");
            sb.append(relationMemberTable);
            sb.append("(ID_RELATION BIGINT, ID_SUB_RELATION BIGINT, ROLE VARCHAR, RELATION_ORDER INT);");
            stmt.execute(sb.toString());
        }
        return connection.prepareStatement("INSERT INTO " + relationMemberTable + " VALUES ( ?,?,?,?);");
    }
321670
public function belongsToMany(
        $entity,
        string $related,
        string $table = null,
        string $foreignKey = null,
        string $otherKey = null
    ): BelongsToMany {
        // Add the relation to the definition in map
        list(, $caller) = debug_backtrace(false);
        $relation = $caller['function'];
        $this->relatedClasses[$relation] = $related;

        $this->addManyRelation($relation);
        $this->addForeignRelation($relation);
        $this->addPivotRelation($relation);

        // First, we'll need to determine the foreign key and "other key" for the
        // relationship. Once we have determined the keys we'll make the query
        // instances as well as the relationship instances we need for this.
        $foreignKey = $foreignKey ?: $this->getForeignKey();

        $relatedMapper = Manager::getInstance()->mapper($related);

        $relatedMap = $relatedMapper->getEntityMap();

        $otherKey = $otherKey ?: $relatedMap->getForeignKey();

        // If no table name was provided, we can guess it by concatenating the two
        // models using underscores in alphabetical order. The two model names
        // are transformed to snake case from their default CamelCase also.
        if (is_null($table)) {
            $table = $this->joiningTable($relatedMap);
        }

        return new BelongsToMany($relatedMapper, $entity, $table, $foreignKey, $otherKey, $relation);
    }
58428
public function addForeignColumnName($foreignColumnName)
    {
        if (!is_string($foreignColumnName) || (strlen($foreignColumnName) <= 0)) {
            throw SchemaException::invalidForeignKeyForeignColumnName($this->getName());
        }

        $this->foreignColumnNames[] = $foreignColumnName;
    }
1175877
public void addRemoteRepository(RemoteRepository remoteRepository) {
        if (this.repositoryIds.add(remoteRepository.getId()) ) {
            getRemoteRepositories().add(remoteRepository);
        }
    }
503404
public FKeyModel fkey(String fkeyName) {
		checkReadOnly();
		FKeyModel fkey = new FKeyModel();
		fkey.setTableName(this.tableName);
		fkey.setFkeyName(fkeyName);
		fkey.setTableModel(this);
		getFkeyConstraints().add(fkey);
		return fkey;
	}
1339308
public function addOneToMany($schema, $foreign_id = null, $col = null, $name = null, $one = null)
  {
    $m = $this->getManager();
    $s = $schema instanceof Schema ? $schema : $m->getSchema($schema, true);
    $n = $name ?: $s->getName();

    $this->relations[$n] = array(
      'type'       => static::RELATION_ONE_TO_MANY,
      'column'     => $col ?: $this->getPrimaryKey(),
      'schema'     => $s,
      'foreign_id' => $foreign_id ?: StaticStringy::underscored($this->getItemClass(false) . '_id'),
      'name'       => $n,
      'one'        => $one ?: $s->getItemClass(false),
    );

    return $this;
  }
1209582
private void addJoinTable(List<Relation> relations)
    {
        for (Relation relation : relations)
        {
            if (relation.getType().equals(ForeignKey.MANY_TO_MANY) && relation.isRelatedViaJoinTable())
            {
                String joinTableName = relation.getJoinTableMetadata().getJoinTableName();
                String hTableName = HBaseUtils.getHTableName(databaseName, joinTableName);
                HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(hTableName));
                tableDescriptor.addFamily(new HColumnDescriptor(joinTableName));
                createOrUpdateTable(hTableName, tableDescriptor);
            }
        }
    }
1013315
protected function OneToMany($related, $model, $local, $remote)
    {
        $relationVal = $this->manyRelationValue($related, $model, $local);
        $relationColumn = $this->manyRelationColumn($related, $model, $remote);
        //
        return $this->all($related, $relationColumn, $relationVal);
    }
869766
public function add($fk, $column = null, $keyName = null, $onDelete = null, $onUpdate = null)
    {
        $baseFk = $this->baseFk($fk);

        $column = $column ?: $baseFk->defaultColumn();

        static::$foreignKeys[] = [
            'column'          => $column ?: $this->column,
            'key_name'        => $keyName ?: $this->keyName,
            'table'           => $this->table->getTable(),
            'reference_table' => $baseFk->referenceTable(),
            'primary_key'     => $baseFk->primaryKey,
            'on_delete'       => $onDelete ?: $this->onDelete ?: $baseFk->onDelete,
            'on_update'       => $onUpdate ?: $this->onUpdate ?: $baseFk->onUpdate,
        ];

        return $baseFk->createFkColumn($column);
    }
391572
private void addIndirectionTable(CollectionDescriptorDef collDef)
    {
        String   tableName = collDef.getProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE);
        TableDef tableDef  = getTable(tableName);

        if (tableDef == null)
        {
            tableDef = new TableDef(tableName);
            addTable(tableDef);
        }
        if (collDef.hasProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE_DOCUMENTATION))
        {
            tableDef.setProperty(PropertyHelper.OJB_PROPERTY_TABLE_DOCUMENTATION,
                                 collDef.getProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE_DOCUMENTATION));
        }

        // we add columns for every primarykey in this and the element type
        //   collection.foreignkeys        <-> ownerclass.primarykeys
        //   collection.remote-foreignkeys <-> elementclass.primarykeys
        // we also add foreignkeys to the table
        //   name is empty (default foreignkey)
        //   remote table   = table of ownerclass/elementclass
        //   local columns  = columns in indirection table 
        //   remote columns = columns of corresponding primarykeys in ownerclass/elementclass
        ClassDescriptorDef ownerClassDef    = (ClassDescriptorDef)collDef.getOwner();
        ModelDef           modelDef         = (ModelDef)ownerClassDef.getOwner();
        String             elementClassName = collDef.getProperty(PropertyHelper.OJB_PROPERTY_ELEMENT_CLASS_REF);
        ClassDescriptorDef elementClassDef  = modelDef.getClass(elementClassName);
        ArrayList          localPrimFields  = ownerClassDef.getPrimaryKeys();
        ArrayList          remotePrimFields = elementClassDef.getPrimaryKeys();
        String             localKeyList     = collDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY);
        String             remoteKeyList    = collDef.getProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY);
        String             ownerTable       = getTargetTable(ownerClassDef, tableName, localKeyList);
        String             elementTable     = getTargetTable(elementClassDef, tableName, remoteKeyList);
        CommaListIterator  localKeys        = new CommaListIterator(localKeyList);
        CommaListIterator  localKeyDocs     = new CommaListIterator(collDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY_DOCUMENTATION));
        CommaListIterator  remoteKeys       = new CommaListIterator(remoteKeyList);
        CommaListIterator  remoteKeyDocs    = new CommaListIterator(collDef.getProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY_DOCUMENTATION));
        ArrayList          localColumns     = new ArrayList();
        ArrayList          remoteColumns    = new ArrayList();
        boolean            asPrimarykeys    = collDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE_PRIMARYKEYS, false);
        FieldDescriptorDef fieldDef;
        ColumnDef          columnDef;
        String             relationName;
        String             name;
        int                idx;

        for (idx = 0; localKeys.hasNext(); idx++)
        {
            fieldDef  = (FieldDescriptorDef)localPrimFields.get(idx);
            name      = localKeys.getNext();
            columnDef = tableDef.getColumn(name);
            if (columnDef == null)
            {
                columnDef = new ColumnDef(name);
                tableDef.addColumn(columnDef);
            }
            columnDef.setProperty(PropertyHelper.TORQUE_PROPERTY_TYPE, fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE));
            columnDef.setProperty(PropertyHelper.TORQUE_PROPERTY_SIZE, fieldDef.getSizeConstraint());
            if (asPrimarykeys)
            {
                columnDef.setProperty(PropertyHelper.TORQUE_PROPERTY_PRIMARYKEY, "true");
            }
            if (localKeyDocs.hasNext())
            {
                columnDef.setProperty(PropertyHelper.OJB_PROPERTY_COLUMN_DOCUMENTATION, localKeyDocs.getNext());
            }
            localColumns.add(name);
            remoteColumns.add(fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_COLUMN));
        }
        if (collDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_DATABASE_FOREIGNKEY, true))
        {
            relationName = collDef.getProperty(PropertyHelper.TORQUE_PROPERTY_RELATION_NAME);
            if ((relationName != null) && (ownerTable != null))
            {
                tableDef.addForeignkey(relationName, ownerTable, localColumns, remoteColumns);
            }
        }
        localColumns.clear();
        remoteColumns.clear();

        for (idx = 0; remoteKeys.hasNext(); idx++)
        {
            fieldDef  = (FieldDescriptorDef)remotePrimFields.get(idx);
            name      = remoteKeys.getNext();

            columnDef = tableDef.getColumn(name);
            if (columnDef == null)
            {
                columnDef = new ColumnDef(name);
                tableDef.addColumn(columnDef);
            }
            columnDef.setProperty(PropertyHelper.TORQUE_PROPERTY_TYPE, fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE));
            columnDef.setProperty(PropertyHelper.TORQUE_PROPERTY_SIZE, fieldDef.getSizeConstraint());
            if (asPrimarykeys)
            {
                columnDef.setProperty(PropertyHelper.TORQUE_PROPERTY_PRIMARYKEY, "true");
            }
            if (remoteKeyDocs.hasNext())
            {
                columnDef.setProperty(PropertyHelper.OJB_PROPERTY_COLUMN_DOCUMENTATION, remoteKeyDocs.getNext());
            }
            localColumns.add(name);
            remoteColumns.add(fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_COLUMN));
        }

        CollectionDescriptorDef elementCollDef = collDef.getRemoteCollection();

        if (((elementCollDef != null) && elementCollDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_DATABASE_FOREIGNKEY, true)) ||
            ((elementCollDef == null) && collDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_DATABASE_FOREIGNKEY, true)))
        {
            relationName = collDef.getProperty(PropertyHelper.TORQUE_PROPERTY_INV_RELATION_NAME);
            if ((relationName != null) && (elementTable != null))
            {
                tableDef.addForeignkey(relationName, elementTable, localColumns, remoteColumns);
            }
        }
    }
236150
public function hasMany(string $related, string $primary_key = '', string $foreign_key = '')
    {
        $relatedModel = app()->make($related);
        $local_key = $local_key ?? $this->getKey();
        // Make the table name singular and append ID to it
        // FIXME: Use a more reliable approach
        $foreign_key = $foreign_key ?? rtrim($relatedModel->getTable(), 's').'_id';
        return new HasMany($relatedModel, $this, $primary_key, $foreign_key);
    }
188603
public function setForeignTableName($foreignTableName)
    {
        if (!is_string($foreignTableName) || (strlen($foreignTableName) <= 0)) {
            throw SchemaException::invalidForeignKeyForeignTableName($this->getName());
        }

        $this->foreignTableName = $foreignTableName;
    }
1150855
protected function addLocalRelation(string $relation)
    {
        if (!in_array($relation, $this->localRelations)) {
            $this->localRelations[] = $relation;
        }
    }
259098
public function hasManyThroughSeveral(array $relations, $foreignKey = null, $localKey = null)
    {
        $helpers = new Helpers($this);
        $currentRelation = current($relations);
        $related = $helpers->getClassNameFromCurrent($currentRelation, $relations);
        $firstRelation = new $related();

        $instance = $this->newRelatedInstance($related);
        $query = $instance
            ->newQuery()
            ->distinct()
            ->select($firstRelation->getTable().'.*');

        $joins = $helpers->getReverseJoinsRelations($relations, $localKey);
        foreach ($joins as $join) {
            $query->join($join['table'], $join['key'], '=', $join['foreign_key']);
        }

        $query->addSelect($join['select_key']);

        $key = $localKey ?? $this->getTable().'.'.$this->getKeyName();
        $value = $this->{$this->getKeyName()};

        $foreignKey = $foreignKey ?? $join['foreign_key'];

        $localKey = $localKey ?? $this->getKeyName();

        $query->where($key, $value);

        return new HasMany($query, $this, $foreignKey, $localKey);
    }
1305088
public void removeRelationship(String baseTableName,
			String relatedTableName, String relationName) {

		try {
			if (extendedRelationsDao.isTableExists()) {
				List<ExtendedRelation> extendedRelations = getRelations(
						baseTableName, relatedTableName, relationName, null);
				for (ExtendedRelation extendedRelation : extendedRelations) {
					removeRelationship(extendedRelation);
				}
			}
		} catch (SQLException e) {
			throw new GeoPackageException("Failed to remove relationship '"
					+ relationName + "' between " + baseTableName + " and "
					+ relatedTableName, e);
		}

	}
1080589
public function setRelation($relation, $relationColumn = null)
    {
        $this->relation = $relation;
        $this->relationColumn = $relationColumn;

        return $this;
    }