Caches a relation for later use.
Creates a new model in case of empty values.

We need to invoke this method for every field
we want to save later, no exception

@param $key
@param $model

@return mixed
511262
protected function createChild($key)
    {
        $relation = $this->getValueOrRelationForKey($key);
        // if this is not a relation, then it's the actual value
        // returned by a method (like for example computed attributes)
        // so we just return it as the value

        if (!$relation instanceof Relation) {
            return $relation;
        }

        $this->supportedRelationOrThrow($key, $relation);

        // TODO we need to bind the relation to the datasource here
        $model = Rel::make($relation)->getChild();

        if (!$this->isEloquentObject($model)) {
            throw new \LogicException(sprintf(
                'newModelFromRelation should return an Eloquent Model/Collection, but returned a %s (parent: %s, key: %s, relation: %s)',
                get_type_class($model),
                get_type_class($this->getDelegatedStorage()), $key, get_type_class($relation)
            ));
        }

        return $model;
    }
141833
public function updateDataKeyObj( $model, $meta ) {

		$data	= $model->getDataMeta( 'data' );
		$key	= $meta->key;
		$data	= !empty( $data ) ? $data : new \StdClass();

		$data->$key = $meta->value;

		$model->updateDataMeta( 'data', $data );

		$model->refresh();

		return $model;
	}
670530
public function createFromModel(Model $model)
    {
        $this->model = $model;
        $this->query = $this->model->newQuery();

        return $this;
    }
467465
public function get($key) {
        $value = null;

        // If the key already exists in the attribute list, return it immediately
        if ($this->has($key)) {
            $value = $this->_attributes[$key];
        }

        // If the key being accessed points to a relation, either lazy load the data or return the cached data
        if (!$value && $this->hasRelation($key)) {
            $value = $this->getRelation($key)->fetchRelation();

            $this->set($key, $value);

        // If an accessor has been defined, run the value through the accessor before returning
        } else if ($method = $this->hasAccessor($key)) {
            $value = $this->{$method}($value);
        }

        return $value;
    }
1191191
protected function getModel($key)
    {
        if (!array_key_exists($key, $this->models)) {
            list($namespace, $key) = $this->splitNamespaceAndKey($key);

            $this->models[$key] = Config::query()
                                        ->where(Config::FIELD_NAMESPACE, $namespace)
                                        ->where(Config::FIELD_KEY, $key)
                                        ->first();

            // Cache if data is found in database
            if ($this->models[$key] !== null) {
                $this->cache->forever($key, $this->models[$key]->value);
            }
        }

        return $this->models[$key];
    }
3335
private function doCommitCreate(Model $model)
    {
        $this->dispatchLifecycleEvent(Events::preCreate, $model);

        $this->getPersisterFor($model->getType())->create($model);
        $model->getState()->setNew(false);
        // Should the model always reload? Or should the commit be assumed correct and just clear the new/dirty state?
        $model->reload();

        $this->dispatchLifecycleEvent(Events::postCreate, $model);
        return $model;
    }
375880
protected function saveRelationsAfterHasOne($key)
    {
        /** @var \T4\Orm\Model $class */
        $class = get_class($this);
        $relation = $class::getRelations()[$key];
        $column = $class::getRelationLinkName($relation);

        /** @var \T4\Orm\Model $oldSubModel */
        $oldSubModel = $this->getRelationLazy($key);

        /** @var \T4\Orm\Model $newSubModel */
        $newSubModel = $this->{$key};

        if ( !empty($oldSubModel) && (empty($newSubModel) || $newSubModel->getPk() != $oldSubModel->getPk()) ) {
            $oldSubModel->{$column} = null;
            $oldSubModel->save();
        }

        if ( !empty($newSubModel) ) {
            $newSubModel->{$column} = $this->getPk();
            $newSubModel->save();
        }
    }
858682
public function duplicate($model, $relation = null) {
		$clone = $this->cloneModel($model);
		$this->duplicateAttachments($clone);
		$this->saveClone($clone, $relation, $model);
		$this->cloneRelations($model, $clone);
		return $clone;
	}
469232
protected function makeModelFormFieldDataForRelationData(ModelRelationData $relation, $key = null)
    {
        $required = (   in_array($relation->type, [
                            RelationType::BELONGS_TO,
                            RelationType::BELONGS_TO_THROUGH,
                            RelationType::MORPH_TO,
                        ])
                    &&  ! $relation->nullable_key);

        // Shows any relation, regardless of type. Note that this is not optimal for
        // records with a large number of to-many related items, for instance.

        return new ModelFormFieldData([
            'key'              => $key ?: $relation->name,
            'source'           => $relation->method,
            'required'         => $required,
            'translated'       => $relation->translated,
            'display_strategy' => $this->determineFormDisplayStrategyForRelation($relation),
            'store_strategy'   => $this->determineFormStoreStrategyForRelation($relation),
            'options'          => $this->determineFormStoreOptionsForRelation($relation),
        ]);
    }
1096854
protected function cloneRelations($model, $clone) {
		if (!method_exists($model, 'getCloneableRelations')) return;
		foreach($model->getCloneableRelations() as $relation_name) {
			$this->duplicateRelation($model, $relation_name, $clone);
		}
	}
521066
public function cacheKey(Model $model, $keys, $prefix = true)
    {

        // TranslateBehavior support
        if (!empty($model->locale)) {
            $keys = array_merge((array)$model->locale, (array)$keys);
        }

        if (is_array($keys)) {
            $key = array_shift($keys);

            if ($keys) {
                foreach ($keys as $value) {
                    if (is_array($value)) {
                        $key .= '-' . md5(json_encode($value));
                    } else if ($value) {
                        $key .= '-' . $value;
                    }
                }
            }
        } else {
            $key = (string)$keys;
        }

        if ($prefix) {
            $key = (string)$this->settings[$model->alias]['prefix'] . $key;
        }

        // Replace AppModel with the current Model so we don't run into conflicts
        $key = str_replace(array('AppModel', '::'), array($model->alias, '_'), $key);

        return $key;
    }
129252
protected function saveRelationsAfterHasMany($key)
    {
        /** @var \T4\Orm\Model $class */
        $class = get_class($this);
        $relation = $class::getRelations()[$key];
        $column = $class::getRelationLinkName($relation);

        /** @var \T4\Core\Collection $oldSubModelsSet */
        $oldSubModelsSet = $this->getRelationLazy($key);
        /** @var \T4\Core\Collection $newSubModelsSet */
        $newSubModelsSet = $this->{$key};

        $toDeletePks =
            array_diff(
                $oldSubModelsSet->collect($relation['model']::PK),
                $newSubModelsSet->collect($relation['model']::PK)
            );

        foreach ($toDeletePks as $toDeletePk) {
            /** @var \T4\Orm\Model $subModel */
            $subModel = $oldSubModelsSet->findByAttributes([$relation['model']::PK => $toDeletePk]);
            $subModel->{$column} = null;
            $subModel->save();
        }

        foreach ( $newSubModelsSet ?: [] as $subModel ) {
            /** @var \T4\Orm\Model $subModel */
            $subModel->{$column} = $this->getPk();
            $subModel->save();
        }
    }
971008
protected function getModelsByKey($model, $keys)
    {
        if (is_string($model)) {
            $model = new $model;
        }

        /** @var Model $model */
        return $model->withoutGlobalScopes()
            ->whereIn($model->getKeyName(), $keys)
            ->get()
            ->keyBy($model->getKeyName());
    }
520925
protected function createAssignRecords(Model $model, array $keys)
    {
        $type = $model->getMorphClass();

        return array_map(function ($key) use ($type) {
            return Models::scope()->getAttachAttributes() + [
                'role_id'     => $this->getKey(),
                'entity_type' => $type,
                'entity_id'   => $key,
            ];
        }, $keys);
    }
764250
public function creating(Model $model)
    {
        $count = method_exists($model, 'getCounter') ? $model->getCounter() : ($model::count() ?? 0);

        $column = method_exists($model, 'getReferenceColumn') ? $model->getReferenceColumn() : 'reference';

        $prefix = method_exists($model, 'referencePrefix') ? $model->referencePrefix() : config('document.prefix');

        if (Schema::hasColumn($model->getTable(), $column) && is_null($model->$column)) {
            $model->$column = generate_reference($prefix, $count);
        }
    }
1223159
public function fromModel($model, string $name, string $key = null): self
    {
        /* @var $model Model */
        $model = is_object($model) ? $model : new $model();
        $key = $key ?? $model->getModel()->getKeyName();

        return $this->setFromEloquent($model, $name, $key);
    }
1270484
protected function getModelByKey(Model $model, $key)
    {
        return $model::withoutGlobalScopes()
            ->where($model->getKeyName(), $key)
            ->first();
    }