Define a many-to-many relationship.

@param  string  $related
@param  string  $table
@param  string  $foreignKey
@param  string  $relatedKey
@param  string  $relation
@return \Globalis\PuppetSkilled\Database\Magic\Relations\BelongsToMany
167001
public function belongsToMany($related, $table = null, $foreignKey = null, $relatedKey = null, $relation = null)
    {
        // If no relationship name was passed, we will pull backtraces to get the
        // name of the calling function. We will use that function name as the
        // title of this relation since that is a great convention to apply.
        if (is_null($relation)) {
            $relation = $this->guessBelongsToManyRelation();
        }

        // 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.
        $instance = $this->newRelatedInstance($related);

        $foreignKey = $foreignKey ?: $this->getForeignKey();

        $relatedKey = $relatedKey ?: $instance->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($related);
        }

        return new BelongsToMany(
            $instance->newQuery(), $this, $table, $foreignKey, $relatedKey, $relation
        );
    }
876074
protected function addManyRelation(string $relation)
    {
        if (!in_array($relation, $this->manyRelations)) {
            $this->manyRelations[] = $relation;
        }
    }
1091179
public static function related_class($relation)
	{
		$class = get_called_class();

		foreach (static::$_valid_relations as $rel_name => $rel_class)
		{
			if (property_exists($class, '_'.$rel_name))
			{
				if (isset(static::${'_'.$rel_name}[$relation]))
				{
					return static::${'_'.$rel_name}[$relation]['model_to'];
				}
			}
		}

		return null;
	}
680371
final public function getRelated($relatedProperty) {
		
		$cacheName = $relatedProperty . 'RelatedObject';
		
		// object exists in cache, return it
		if ($this->issetCache($cacheName)) {
			return $this->getCache($cacheName);
		}
		
		// get table foreign-keys
		$foreignKeys = $this->db->getForeignKeys(static::TABLE_NAME);
		
		// get field name by mapped property
		$relatedField = $this->getMappedField($relatedProperty);
		
		// the table referenced by fk
		$referencedTable = NULL;
			
		// search the fk-table
		foreach ($foreignKeys as $fk) {
			if ($fk->COLUMN_NAME == $relatedField) {
				$referencedTable  = $fk->REFERENCED_TABLE_NAME;
				$referencedColumn = $fk->REFERENCED_COLUMN_NAME;
				break;
			}
		}
		
		// if not table is referenced, raise an error
		if (!$referencedTable) {
			$this->addError('Property ' . $relatedProperty . ' has not a foreign-key mapped into DB');
			return NULL;
		}
		
		// class that maps the referenced table
		$relatedClass = NULL;
		$loadedClasses = \get_declared_classes();
		
		// search in loaded classes
		foreach ($loadedClasses as $c) {
			if (is_subclass_of($c, 'Pair\ActiveRecord') and property_exists($c, 'TABLE_NAME') and $c::TABLE_NAME == $referencedTable) {
				$relatedClass = $c;
				break;
			}
		}
			
		// class cannot be found
		if (!$relatedClass) {
			
			// if not found, search in the whole application (FIXME encapsulation violated here...)
			$classes = Utilities::getActiveRecordClasses();
			
			// search for required one
			foreach ($classes as $class => $opts) {
				if ($opts['tableName'] == $referencedTable) {
					include_once($opts['folder'] . '/' . $opts['file']);
					$relatedClass = $class;
					break;
				}
			}
			
		}
		
		// class cannot be found
		if (!$relatedClass) {
			$this->addError('Table ' . $referencedTable . ' has not any Pair-class mapping');
			return NULL;
		}
		
		// create the new wanted Pair object
		$obj = new $relatedClass($this->$relatedProperty);
		
		// if loaded, return it otherwise NULL
		$ret = ($obj->isLoaded() ? $obj : NULL);
		
		// related object is being registered in cache of this object
		$this->setCache($cacheName, $ret);
		
		return $ret;
		
	}
1039270
protected function joinBelongsToMany(BelongsToMany $relation)
    {
        return $this->instance->join(
            $relation->getTable(),
            $relation->getParent()->getTable() . '.' . $relation->getParent()->getKeyName(),
            '=',
            $relation->getForeignKey()
        )->join(
            $relation->getRelated()->getTable(),
            $relation->getRelated()->getTable() . '.' . $relation->getRelated()->getKeyName(),
            '=',
            $relation->getOtherKey()
        );
    }
1337819
public function foreignMany($related, $foreignKey = null, $localKey = null)
    {
        $instance = new $related;

        $foreignKey = $foreignKey ?: Str::snake(class_basename($this)).'_id';

        $localKey = $localKey ?: '_id';

        return new ForeignMany($this, $instance->query(['*']), $foreignKey, $localKey);
    }
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);
    }
1091695
public function joiningTable($related)
    {
        // The joining table name, by convention, is simply the snake cased models
        // sorted alphabetically and concatenated with an underscore, so we can
        // just sort the models and join them together to get the table name.
        $models = [
            str_snake(class_basename($this)),
            str_snake(class_basename($related))
        ];

        // Now that we have the model names in an array we can just sort them and
        // use the implode function to join them together with an underscores,
        // which is typically used by convention within the database system.
        sort($models);

        return strtolower(implode('_', $models));
    }
754301
protected function hasOneOrManyDeepForeignKeys(Model $related, array $throughParents, array $foreignKeys)
    {
        foreach (array_merge([$this], $throughParents) as $i => $instance) {
            /** @var \Illuminate\Database\Eloquent\Model $instance */
            if (! isset($foreignKeys[$i])) {
                if ($instance instanceof Pivot) {
                    $foreignKeys[$i] = ($throughParents[$i] ?? $related)->getKeyName();
                } else {
                    $foreignKeys[$i] = $instance->getForeignKey();
                }
            }
        }

        return $foreignKeys;
    }
548815
public function hasManyDeep($related, array $through, array $foreignKeys = [], array $localKeys = [])
    {
        return $this->newHasManyDeep(...$this->hasOneOrManyDeep($related, $through, $foreignKeys, $localKeys));
    }
1058161
public function belongsToMany($related, $table = null, $foreignKey = null, $otherKey = null, $relation = null)
    {
        // If no relationship name was passed, we will pull backtraces to get the
        // name of the calling function. We will use that function name as the
        // title of this relation since that is a great convention to apply.
        if (is_null($relation)) {
            $relation = $this->getBelongsToManyCaller();
        }

        $foreignKey = $foreignKey ?: $this->getCmsReferenceKeyForRelation($relation);
        $otherKey   = $otherKey   ?: $this->getCmsReferenceKeyForRelation($relation, true);

        if (is_null($table)) {
            $table = $this->getCmsJoiningTable();
        }

        $fieldId = $this->getCmsReferenceFieldId($relation);
        if (empty($fieldId)) {
            throw new InvalidArgumentException("No 'field' id configured for relation/reference: '{$relation}'!");
        }

        // originally, it was possible to just get the parent's BelongsToMany instance, but
        // to avoid problems when saving on the relationship, we need a specialized extension
        // of the relation class for the CMS.
        //$belongsToMany = parent::belongsToMany($related, $table, $foreignKey, $otherKey);

        /** @var Model $instance */
        $instance = new $related;

        $query = $instance->newQuery();

        $belongsToMany = new BelongsToMany($query, $this, $table, $foreignKey, $otherKey, $relation, $fieldId);

        // add constraints
        $belongsToMany->wherePivot(config('pxlcms.relations.references.keys.field', 'from_field_id'), $fieldId);

        return $belongsToMany;
    }
473552
public function hasMany($related, $parentKey = null, $localKey = null)
    {
        $parentKey = $parentKey ?: $this->getParentKey();
        $localKey = $localKey ?: $this->getKeyName();

        $instance = new $related;

        return new Relations\Relation($instance, $this, $parentKey, $localKey);
    }
879645
public function joiningTable($related)
	{
		// The joining table name, by convention, is simply the snake cased models
		// sorted alphabetically and concatenated with an underscore, so we can
		// just sort the models and join them together to get the table name.
		$base = snake_case(class_basename($this));

		$related = snake_case(class_basename($related));

		$models = array($related, $base);

		// Now that we have the model names in an array we can just sort them and
		// use the implode function to join them together with an underscores,
		// which is typically used by convention within the database system.
		sort($models);

		return strtolower(implode('_', $models));
	}
305759
protected function newPivotQuery(BelongsToMany $relation)
    {
        $query = $relation->newPivotStatement()->where(
            $this->getForeignPivotKeyName($relation),
            $relation->getParent()->getKey()
        );

        return Models::scope()->applyToRelationQuery(
            $query, $relation->getTable()
        );
    }
1143708
public function hasMany($entity, string $related, string $foreignKey = null, string $localKey = null): HasMany
    {
        $foreignKey = $foreignKey ?: $this->getForeignKey();

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

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

        // 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);

        return new HasMany($relatedMapper, $entity, $foreignKey, $localKey);
    }
1241537
protected function has_many( $model, $foreign_key = null, $local_key = null )
	{
		return new Model_Relation_HasMany( $this, $model, $foreign_key, $local_key );
	}
242025
public function hasMany(Model $related)
    {
        $table = ucfirst($related->getTable());
        $column = "shared{$table}List";
        $this->bean->$column[] = $related->getBean();
    }