<commit_before><?php namespace Vinelab\NeoEloquent\Eloquent\Relations;

use Vinelab\NeoEloquent\Eloquent\Model;
use Vinelab\NeoEloquent\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Vinelab\NeoEloquent\Eloquent\Edges\EdgeIn;
use Vinelab\NeoEloquent\Eloquent\Edges\EdgeOut;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Model as EloquentModel;

class BelongsToMany extends HasOneOrMany {

    /**
     * The relationship name.
     *
     * @var string
     */
    protected $relation;

    /**
     * The relationship type, which is the label to be used
     * in the relationship between models.
     *
     * @var string
     */
    protected $type;

    /**
     * The key that we should query with.
     *
     * @var string
     */
    protected $key;

    public function __construct(Builder $query, Model $parent, $type, $key, $relation)
    {
        parent::__construct($query, $parent, $type, $key, $relation);

        $this->finder = $this->newFinder();
    }

    /**
     * Initialize the relation on a set of models.
     *
     * @param  array   $models
     * @param  string  $relation
     * @return array
     */
    public function initRelation(array $models, $relation)
    {
        foreach ($models as $model)
        {
            $model->setRelation($relation, $this->related->newCollection());
        }

        return $models;
    }

    /**
     * Get the results of the relationship.
     *
     * @return mixed
     */
    public function getResults()
    {
        return $this->query->get();
    }

    /**
     * Match the eagerly loaded results to their parents.
     *
     * @param  array   $models
     * @param  \Illuminate\Database\Eloquent\Collection  $results
     * @param  string  $relation
     * @return array
     */
    public function match(array $models, Collection $results, $relation)
    {
        return $this->matchOneOrMany($models, $results, $relation, 'many');
    }

    /**
     * Set the constraints for an eager load of the relation.
     *
     * @param  array  $models
     * @return void
     */
    public function addEagerConstraints(array $models)
    {
        /**
         * We'll grab the primary key name of the related models since it could be set to
         * a non-standard name and not "id". We will then construct the constraint for
         * our eagerly loading query so it returns the proper models from execution.
         */

        // Grab the parent node placeholder
        $parentNode = $this->query->getQuery()->modelAsNode($this->parent->getTable());

        // Tell the builder to select both models of the relationship
        $this->query->select($this->relation, $parentNode);

        // Setup for their mutation so they don't breed weird stuff like... humans ?!
        $this->query->addManyMutation($this->relation, $this->related, 'many');
        $this->query->addManyMutation($parentNode, $this->parent, 'many');

        // Set the parent node's placeholder as the RETURN key.
        $this->query->getQuery()->from = array($parentNode);
        // Build the MATCH ()-[]->() Cypher clause.
        $this->query->matchOut($this->parent, $this->related, $this->relation, $this->foreignKey, $this->localKey, $this->parent->{$this->localKey});
        // Add WHERE clause over the parent node's matching keys [values...].
        $this->query->whereIn($this->localKey, $this->getKeys($models));
    }

    /**
     * Get the edge between the parent model and the given model or
     * the related model determined by the relation function name.
     *
     * @param  \Illuminate\Database\Eloquent\Model $model
     * @return \Vinelab\NeoEloquent\Eloquent\Edges\Edge[In|Out]
     */
    public function edge(Model $model = null)
    {
        return $this->finder->first($this->parent, $model, $this->type);
    }

    /**
     * Get an instance of the Edge[In|Out] relationship.
     *
     * @param  \Illuminate\Database\Eloquent\Model $model
     * @param  array         $attributes
     * @return \Vinelab\NeoEloquent\Eloquent\Edges\Edge[In|Out]
     */
    public function getEdge(EloquentModel $model = null, $attributes = array())
    {
        $model = ( ! is_null($model)) ? $model : $this->related;

        return new EdgeOut($this->query, $this->parent, $model, $this->type, $attributes);
    }

    /**
     * Attach a model to the parent.
     *
     * @param  mixed  $id
     * @param  array  $attributes
     * @param  bool   $touch
     * @return void
     */
    public function attach($id, array $attributes = array(), $touch = true)
    {
        $models = $id;

        if ($id instanceof Model)
        {
            $models = [$id];
        } elseif ($id instanceof Collection)
        {
            $models = $id->all();
        } elseif ( ! $this->isArrayOfModels($id))
        {
            $models = $this->modelsFromIds($id);
            // In case someone is messing with us and passed a bunch of ids (or single id)
            // that do not exist we slap them in the face with a ModelNotFoundException.
            // There must be at least a record found as for the records that do not match
            // they will be ignored and forever forgotten, poor thing.
            if (count($models) < 1) throw new ModelNotFoundException;

            $models = $models->all();
        }

        $saved = $this->saveMany($models, $attributes);

        if ($touch) $this->touchIfTouching();

        return ( ! is_array($id)) ? $saved->first() : $saved;
    }

    /**
     * Detach models from the relationship.
     *
     * @param  int|array  $ids
     * @param  bool  $touch
     * @return int
     */
    public function detach($id = array(), $touch = true)
    {
        if ( ! $id instanceof Model and ! $id instanceof Collection)
        {
            $id = $this->modelsFromIds($id);
        }

        // Prepare for a batch operation to take place so that we don't
        // overwhelm the database with many delete hits.
        $this->finder->prepareBatch();

        foreach ($id as $model)<commit_msg>fix an issue in the BelongsToMany relationship<commit_after><?php namespace Vinelab\NeoEloquent\Eloquent\Relations;

use Vinelab\NeoEloquent\Eloquent\Model;
use Vinelab\NeoEloquent\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Vinelab\NeoEloquent\Eloquent\Edges\EdgeIn;
use Vinelab\NeoEloquent\Eloquent\Edges\EdgeOut;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Model as EloquentModel;

class BelongsToMany extends HasOneOrMany {

    /**
     * The relationship name.
     *
     * @var string
     */
    protected $relation;

    /**
     * The relationship type, which is the label to be used
     * in the relationship between models.
     *
     * @var string
     */
    protected $type;

    /**
     * The key that we should query with.
     *
     * @var string
     */
    protected $key;

    public function __construct(Builder $query, Model $parent, $type, $key, $relation)
    {
        parent::__construct($query, $parent, $type, $key, $relation);

        $this->finder = $this->newFinder();
    }

    /**
     * Initialize the relation on a set of models.
     *
     * @param  array   $models
     * @param  string  $relation
     * @return array
     */
    public function initRelation(array $models, $relation)
    {
        foreach ($models as $model)
        {
            $model->setRelation($relation, $this->related->newCollection());
        }

        return $models;
    }

    /**
     * Get the results of the relationship.
     *
     * @return mixed
     */
    public function getResults()
    {
        return $this->query->get();
    }

    /**
     * Match the eagerly loaded results to their parents.
     *
     * @param  array   $models
     * @param  \Illuminate\Database\Eloquent\Collection  $results
     * @param  string  $relation
     * @return array
     */
    public function match(array $models, Collection $results, $relation)
    {
        return $this->matchOneOrMany($models, $results, $relation, 'many');
    }

    /**
     * Set the constraints for an eager load of the relation.
     *
     * @param  array  $models
     * @return void
     */
    public function addEagerConstraints(array $models)
    {
        /**
         * We'll grab the primary key name of the related models since it could be set to
         * a non-standard name and not "id". We will then construct the constraint for
         * our eagerly loading query so it returns the proper models from execution.
         */

        // Grab the parent node placeholder
        $parentNode = $this->query->getQuery()->modelAsNode($this->parent->getTable());

        // Tell the builder to select both models of the relationship
        $this->query->select($this->relation, $parentNode);

        // Setup for their mutation so they don't breed weird stuff like... humans ?!
        $this->query->addManyMutation($this->relation, $this->related);
        $this->query->addManyMutation($parentNode, $this->parent);

        // Set the parent node's placeholder as the RETURN key.
        $this->query->getQuery()->from = array($parentNode);
        // Build the MATCH ()-[]->() Cypher clause.
        $this->query->matchOut($this->parent, $this->related, $this->relation, $this->foreignKey, $this->localKey, $this->parent->{$this->localKey});
        // Add WHERE clause over the parent node's matching keys [values...].
        $this->query->whereIn($this->localKey, $this->getKeys($models));
    }

    /**
     * Get the edge between the parent model and the given model or
     * the related model determined by the relation function name.
     *
     * @param  \Illuminate\Database\Eloquent\Model $model
     * @return \Vinelab\NeoEloquent\Eloquent\Edges\Edge[In|Out]
     */
    public function edge(Model $model = null)
    {
        return $this->finder->first($this->parent, $model, $this->type);
    }

    /**
     * Get an instance of the Edge[In|Out] relationship.
     *
     * @param  \Illuminate\Database\Eloquent\Model $model
     * @param  array         $attributes
     * @return \Vinelab\NeoEloquent\Eloquent\Edges\Edge[In|Out]
     */
    public function getEdge(EloquentModel $model = null, $attributes = array())
    {
        $model = ( ! is_null($model)) ? $model : $this->related;

        return new EdgeOut($this->query, $this->parent, $model, $this->type, $attributes);
    }

    /**
     * Attach a model to the parent.
     *
     * @param  mixed  $id
     * @param  array  $attributes
     * @param  bool   $touch
     * @return void
     */
    public function attach($id, array $attributes = array(), $touch = true)
    {
        $models = $id;

        if ($id instanceof Model)
        {
            $models = [$id];
        } elseif ($id instanceof Collection)
        {
            $models = $id->all();
        } elseif ( ! $this->isArrayOfModels($id))
        {
            $models = $this->modelsFromIds($id);
            // In case someone is messing with us and passed a bunch of ids (or single id)
            // that do not exist we slap them in the face with a ModelNotFoundException.
            // There must be at least a record found as for the records that do not match
            // they will be ignored and forever forgotten, poor thing.
            if (count($models) < 1) throw new ModelNotFoundException;

            $models = $models->all();
        }

        $saved = $this->saveMany($models, $attributes);

        if ($touch) $this->touchIfTouching();

        return ( ! is_array($id)) ? $saved->first() : $saved;
    }

    /**
     * Detach models from the relationship.
     *
     * @param  int|array  $ids
     * @param  bool  $touch
     * @return int
     */
    public function detach($id = array(), $touch = true)
    {
        if ( ! $id instanceof Model and ! $id instanceof Collection)
        {
            $id = $this->modelsFromIds($id);
        } elseif ( ! is_array($id))
        {
            $id = [$id];
        }

        // Prepare for a batch operation to take place so that we don't
        // overwhelm the database with many delete hits.
        $this->finder->prepareBatch();

        foreach ($id as $model)
{'fraction_non_alphanumeric': 0.12506098552610181, 'fraction_numerical': 0.0001626280696048138, 'mean_word_length': 2.229779411764706, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 121, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5323734', 'n_tokens_mistral': 3610, 'n_tokens_neox': 3564, 'n_words': 1039}