Executes a detach on the model provided

@param  Model $model
@param  string   $relation name of the relation (method name)
@param  array    $ids
@param  boolean  $touch
@return
@internal param array $attributes
165218
public function detach(Model $model, $relation, $ids = array(), $touch = true)
    {
        return $model->{$relation}()->detach($ids, $touch);
    }
260117
private function _getRelatedFks($data, $relation, $modelClass)
    {
        $fks = [];
        if (is_array($data)) {
            // Get the right link definition
            if ($relation->via instanceof BaseActiveRecord) {
                $link = $relation->via->link;
            } elseif (is_array($relation->via)) {
                list($viaName, $viaQuery) = $relation->via;
                $link = $viaQuery->link;
            } else {
                $link = $relation->link;
            }
            // search PK
            foreach ($modelClass::primaryKey() as $modelAttribute) {
                if (isset($data[$modelAttribute])) {
                    $fks[$modelAttribute] = $data[$modelAttribute];
                } elseif ($relation->multiple && !$relation->via) {
                    foreach ($link as $relatedAttribute => $relatedModelAttribute) {
                        if (!isset($data[$relatedAttribute]) && in_array($relatedAttribute, $modelClass::primaryKey())) {
                            $fks[$relatedAttribute] = $this->owner->{$relatedModelAttribute};
                        }
                    }
                } else {
                    $fks = [];
                    break;
                }
            }
            if (empty($fks)) {
                foreach ($link as $relatedAttribute => $modelAttribute) {
                    if (isset($data[$modelAttribute])) {
                        $fks[$modelAttribute] = $data[$modelAttribute];
                    }
                }
            }
        } else {
            $fks = $data;
        }
        return $fks;
    }
145100
protected function handleAutoRelatedAttributes($attributes, $model)
    {
        collect($this->getDataKeys())
            ->filter(function ($key) {
                return strpos($key, ':') !== false;

            })->map(function ($key) {
                return array_merge([$key], explode(':', $key));

            })->each(function ($key) use (&$attributes, $model) {
                // For each one, we create a "relation:attribute" key
                // in the returned array
                $attributes[$key[0]] = $model->{$key[1]} ? ($model->{$key[1]}->{$key[2]} ?? null) : null;
            });

        return $attributes;
    }
553255
public function unlink($model, $ids)
	{
		$params = $this->buildParams(array(
			$model,
			'unlink',
			$ids
		));

		return $this->getClient('object')->call('execute', $params);
	}
924080
private function _checkRelationExists(Model $model, string $relationName)
    {
        if (!method_exists($model, $relationName) || !$model->{$relationName}() instanceof Relation) {
            if (Lang::has('resource-controller.data2relationinexistent')) {
                $message = trans('resource-controller.data2relationinexistent', ['relationName' => $relationName]);
            } else {
                $message = "Array type request data '{$relationName}' must be named after an existent relation.";
            }

            throw new MassAssignmentException($message);
        }
    }
198493
public static function getRelationGridColumns($model, $fields, $relationName, $relation)
    {
        $columns = parent::getRelationGridColumns($model, $fields, $relationName, $relation);
        $controller = Yii::$app->crudModelsMap[$model::className()];
        $actionColumn = new \yii\grid\ActionColumn();

        if (!isset($columns[0]) || !isset($columns[0]['class']) || $columns[0]['class'] !== 'yii\grid\ActionColumn') {
            array_unshift($columns, [
                'class'         => 'yii\grid\ActionColumn',
                'headerOptions' => ['class' => 'column-action'],
                'controller'    => $controller,
                'template'      => '',
                'buttons'       => [],
            ]);
        }

        $columns[0]['template'] = '{update} {unlink}';
        $columns[0]['urlCreator'] = function ($action, $model, $key, $index) use ($controller, $relation) {
            $params = is_array($key) ? $key : ['id' => (string)$key];
            if ($action === 'update') {
                $params['hide'] = implode(',', array_keys($relation->link));
            }
            $params[0] = $controller . '/' . $action;

            return Url::toRoute($params);
        };
        $columns[0]['buttons']['update'] = function ($url, $model, $key) use ($actionColumn, $relationName) {
            /** @var \netis\crud\db\ActiveRecord $model */
            if (!Yii::$app->user->can($model::className() . '.update', ['model' => $model])) {
                return null;
            }

            $options = array_merge([
                'title'         => Yii::t('app', 'Update'),
                'aria-label'    => Yii::t('app', 'Update'),
                'data-pjax'     => '0',
                // required for editing in a modal
                'data-toggle'   => 'modal',
                'data-target'   => '#relationModal',
                'data-relation' => $relationName,
                'data-title'    => $model->getCrudLabel('update'),
                'data-pjax-url' => $url,
                'class'         => 'btn btn-default btn-xs',
            ], $actionColumn->buttonOptions);
            return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, $options);
        };

        /** @var \yii\db\ActiveQuery $relation */
        $remove = false;
        $modelClass = $relation->modelClass;
        foreach (array_keys($relation->link) as $foreignKey) {
            $remove = $remove || !$modelClass::getTableSchema()->getColumn($foreignKey)->allowNull;
        }

        $columns[0]['buttons']['unlink'] = function ($url, $model, $key) use ($actionColumn, $remove) {
            /** @var \netis\crud\db\ActiveRecord $model */
            if (!Yii::$app->user->can($model::className() . ($remove ? '.delete' : '.update'), ['model' => $model])) {
                return null;
            }

            $options = array_merge([
                'title'      => Yii::t('app', 'Unlink'),
                'aria-label' => Yii::t('app', 'Unlink'),
                //'data-confirm' => Yii::t('app', 'Are you sure you want to unlink this item?'),
                'data-pjax'  => '0',
                'class'      => 'remove btn btn-default btn-xs',
            ], $actionColumn->buttonOptions);
            return Html::a('<span class="glyphicon glyphicon-remove"></span>', $url, $options);
        };
        return $columns;
    }
735451
protected function processModelAsArray($data, $relation, $name)
    {
        /** @var BaseActiveRecord $modelClass */
        $modelClass = $relation->modelClass;
        $fks = $this->_getRelatedFks($data, $relation, $modelClass);
        return $this->_loadOrCreateRelationModel($data, $fks, $modelClass, $name);
    }
711064
public function match(array $models, Collection $results, $relation)
    {
        // This relationship deals with a One-To-One morph type so we'll just extract
        // the first model out of the results and return it.
        $matched = parent::match($models, $results, $relation);

        return array_map(function($match) use ($relation)
        {
            if (isset($match[$relation]) && isset($match[$relation][0]))
            {
                $match->setRelation($relation, $match[$relation][0]);
            }

            return $match;

        }, $matched);
    }
1103741
public function doDelete($model, $id)
    {
        if ($this->weak) {
            return;
        }

        $delete = $this->dsql();
        if ($this->reverse) {
            $delete->where($this->foreign_field, $this->owner->id);
        } else {
            $delete->where($this->foreign_field, $this->owner[$this->master_field]);
        }

        $delete->delete()->execute();
    }
929226
protected function getJoinClause(Model $parent, Relation $relation, $table, $type)
    {
        list($fk, $pk) = $this->getJoinKeys($relation);

        $join = (new Join($this->query, $type, $table))->on($fk, '=', $pk);

        if (in_array(SoftDeletes::class, class_uses_recursive($relation->getRelated()))) {
            $join->whereNull($relation->getRelated()->getQualifiedDeletedAtColumn());
        }

        if ($relation instanceof MorphOneOrMany) {
            $join->where($relation->getQualifiedMorphType(), '=', $parent->getMorphClass());
        } elseif ($relation instanceof MorphToMany || $relation instanceof MorphByMany) {
            $join->where($relation->getMorphType(), '=', $parent->getMorphClass());
        }

        return $join;
    }
365983
protected function fetchDefinition(ModelInterface $model, $relation)
    {
        if ($model->hasRelation($relation)) {
            return $model->relation($relation);
        }

        throw new RelationException(sprintf('Unable to resolve relation "%s" not found in model "%s"', $relation, $model->entity()));
    }
719492
public function detach($model, string $relation, Model $value)
    {
        if (! $model instanceof Model) {
            $model = $this->find($model);
        }

        $model->$relation()->detach($value);
    }
993876
public function getAPIAttributes($params=array(), $relations = false)
    {
        $attributes = array();
        foreach ($this->attributes as $k=>$v)
        {
        	if (in_array($k, $params))
        		continue;

            $attributes[$k] = $v;
        }

        if ($relations != false)
        {
	        foreach ($relations as $relation=>$params)
	        {
	        	if (is_integer($relation))
	        	{
	        		$relation = $params;
	        		$params = array();
	        	}

	        	if (is_array($this->$relation))
	        	{
	        		$attributes[$relation] = array();
	        		foreach ($this->$relation as $k)
	        			$attributes[$relation][] = $k->getAPIAttributes($params);
	        	}
	        	else
	        	{
	        		if (isset($this->$relation))
	        			$attributes[$relation] = $this->$relation->getAPIAttributes($params);
	        		else
	        			$attributes[$relation] = array();
	        	}
	        }
        }

        return $attributes;
    }
931450
protected function relations($model, $foreignKeyIds)
    {
        $relations = $model->getSoftCascade();

        if (empty($relations)) {
            return;
        }

        foreach ($relations as $relation) {
            extract($this->relationResolver($relation));
            $this->validateRelation($model, $relation);

            $modelRelation = $model->$relation();

            /**
             * Maintains compatibility fot get foreign key name on laravel old and new methods.
             *
             * @link https://github.com/laravel/framework/issues/20869
             */
            $fnUseGetForeignKey = array_intersect($this->fnGetForeignKey, get_class_methods($modelRelation));
            $fnUseGetForeignKey = reset($fnUseGetForeignKey);

            //Get foreign key and foreign key ids
            $foreignKeyUse = $modelRelation->{$fnUseGetForeignKey}();
            $foreignKeyIdsUse = $foreignKeyIds;

            //Many to many relations need to get related ids and related local key
            if ($modelRelation instanceof BelongsToMany) {
                extract($this->getBelongsToManyData($modelRelation, $foreignKeyUse, $foreignKeyIds));
            } elseif ($modelRelation instanceof MorphOneOrMany) {
                extract($this->getMorphManyData($modelRelation, $foreignKeyIds));
            }

            $affectedRows = $this->affectedRows($modelRelation, $foreignKeyUse, $foreignKeyIdsUse);

            if ($action === 'restrict' && $affectedRows > 0) {
                DB::rollBack(); //Rollback the transaction before throw exception
                throw (new SoftCascadeRestrictedException())->setModel(get_class($modelRelation->getModel()), $foreignKeyUse, $foreignKeyIdsUse->toArray());
            }

            $this->execute($modelRelation, $foreignKeyUse, $foreignKeyIdsUse, $affectedRows);
        }
    }
325518
public function createWith(array $attributes, array $relations) {
        // Collect the model attributes and label in the form of ['label' => $label, 'attributes' => $attributes]
        // as expected by the Query Builder.
        $attributes = $this->prepareForCreation($this->model, $attributes);
        $model = ['label' => $this->model->getTable(), 'attributes' => $attributes];

        /**
         * Collect the related models in the following for as expected by the Query Builder:
         *
         *  [
         *       'label' => ['Permission'],
         *       'relation' => [
         *           'name' => 'photos',
         *           'type' => 'PHOTO',
         *           'direction' => 'out',
         *       ],
         *       'values' => [
         *           // A mix of models and attributes, doesn't matter really..
         *           ['url' => '', 'caption' => ''],
         *           ['url' => '', 'caption' => '']
         *       ]
         *  ]
         */
        $related = [];
        foreach ($relations as $relation => $values) {
            $name = $relation;
            // Get the relation by calling the model's relationship function.
            if (!method_exists($this->model, $relation))
                throw new QueryException("The relation method $relation() does not exist on " . get_class($this->model));

            $relationship = $this->model->$relation();
            // Bring the model from the relationship.
            $relatedModel = $relationship->getRelated();

            // We will first check to see what the dev have passed as values
            // so that we make sure that we have an array moving forward
            // In the case of a model Id or an associative array or a Model instance it means that
            // this is probably a One-To-One relationship or the dev decided not to add
            // multiple records as relations so we'll wrap it up in an array.
            if (!is_array($values) || Helpers::isAssocArray($values) || $values instanceof Model)
                $values = [$values];

            $label = $relationship->getRelated()->getTable();
            $direction = $relationship->getEdgeDirection();
            $type = $relationship->getRelationType();

            // Hold the models that we need to attach
            $attach = [];
            // Hold the models that we need to create
            $create = [];
            // Separate the models that needs to be attached from the ones that needs
            // to be created.
            foreach ($values as $value) {
                // If this is a Model then the $exists property will indicate what we need
                // so we'll add its id to be attached.
                if ($value instanceof Model and $value->exists === true) {
                    $attach[] = $value->getKey();
                }
                // Next we will check whether we got a Collection in so that we deal with it
                // accordingly, which guarantees sending an Eloquent result straight in would work.
                elseif ($value instanceof Collection) {
                    $attach = array_merge($attach, $value->lists('id'));
                }
                // Or in the case where the attributes are neither an array nor a model instance
                // then this is assumed to be the model Id that the dev means to attach and since
                // Orientdb node Ids are always an int then we take that as a value.
                elseif (!is_array($value) && !$value instanceof Model) {
                    $attach[] = intval($value);
                }
                // In this case the record is considered to be new to the market so let's create it.
                else
                    $create[] = $this->prepareForCreation($relatedModel, $value);
            }

            $relation = compact('name', 'type', 'direction');
            $related[] = compact('relation', 'label', 'create', 'attach');
        }

        $result = $this->query->createWith($model, $related);

        $models = $this->resultsToModels($this->model->getConnectionName(), $result);
        return (!empty($models)) ? reset($models) : null;
    }
925794
protected function validateRelation($model, $relation)
    {
        $class = get_class($model);
        if (!method_exists($model, $relation)) {
            DB::rollBack(); //Rollback the transaction before throw exception
            throw new \LogicException(sprintf('%s does not have method \'%s\'.', $class, $relation));
        }

        if (!$model->$relation() instanceof \Illuminate\Database\Eloquent\Relations\Relation) {
            DB::rollBack(); //Rollback the transaction before throw exception
            throw new \LogicException(sprintf('%s \'%s\' is not an instance of Illuminate\Database\Eloquent\Relations\Relation.', $class, $relation));
        }
    }
379640
public function detach($ids = null, $touch = true)
    {
        if ($this->using && ! empty($ids) && empty($this->pivotWheres) && empty($this->pivotWhereIns)) {
            $results = $this->detachUsingCustomClass($ids);
        } else {
            $query = $this->newPivotQuery();

            // If associated IDs were passed to the method we will only delete those
            // associations, otherwise all of the association ties will be broken.
            // We'll return the numbers of affected rows when we do the deletes.
            if (! is_null($ids)) {
                $ids = $this->parseIds($ids);

                if (empty($ids)) {
                    return 0;
                }

                $query->whereIn($this->relatedPivotKey, (array) $ids);
            }

            // Once we have all of the conditions set on the statement, we are ready
            // to run the delete on the pivot table. Then, if the touch parameter
            // is true, we will go ahead and touch all related models to sync.
            $results = $query->delete();
        }

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

        return $results;
    }