Default Kind & Schema support for "new" Entities

@param \GDS\Entity[] $arr_entities
355398
protected function ensureSchema($arr_entities)
    {
        foreach($arr_entities as $obj_gds_entity) {
            if($obj_gds_entity instanceof Entity) {
                if (null === $obj_gds_entity->getKind()) {
                    $obj_gds_entity->setSchema($this->obj_schema);
                }
            } else {
                throw new \InvalidArgumentException('You gave me something other than GDS\Entity objects.. not gonna fly!');
            }
        }
    }
31457
public function setEntitiesAttribute($entities): void
    {
        static::saved(function ($model) use ($entities) {
            $this->entities()->delete();
            ! $entities || $this->entities()->createMany(array_map(function ($entity) {
                return ['entity_type' => $entity];
            }, $entities));
        });
    }
1027525
public function init(AType $type, array $defaults = [])
    {
        $type_name = $type->getName();

        $self_fields = ['id','name','from','subject','to','username','email','body','mailed','host','port','encryption','report','password','domain'];

        //[[[
        DB::beginTransaction();

        if($type->getRank() === TypeRank::BLOCK)
        {
            $model = Fbform::where('name', '=', $type_name)->first();

            if(!$model)
            {
                $model = new Fbform();
                $model->name = $type_name;

                foreach(['from','to','subject','username','password','host','port','encryption'] as $field_name)
                {
                    if(array_key_exists($field_name, $defaults))
                    {
                        $model->$field_name = (string) $defaults[$field_name];
                    }
                    else
                    {
                        $model->$field_name = '';
                    }
                }

                $model->save();
            }

            $id = 0;
        }
        elseif($type->getRank() === TypeRank::GROUP)
        {
            $suffix_pos = strripos($type_name, '_');

            if($suffix_pos)
            {
                $suffix = substr($type_name, $suffix_pos+1);
                $name = substr($type_name, 0, $suffix_pos);

                if($suffix === 'mail')
                {
                    $model = new Fbmail();
                    $model->name = $type_name;
                    $model->form_name = $name;

                    foreach(['from','subject','to','username','email','body','host','port','encryption','report'] as $field_name)
                    {
                        if(array_key_exists($field_name, $defaults))
                        {
                            $model->$field_name = (string) $defaults[$field_name];
                        }
                        else
                        {
                            $model->$field_name = '';
                        }
                    }

                    $model->mailed = false;
                }
                elseif($suffix === 'mailto')
                {
                    $model = new Fbmailto();

                    $model->name = $type_name;
                    $model->form_name = $name;

                    if(array_key_exists('to', $defaults))
                    {
                        $model->to = (string) $defaults['to'];
                    }
                    else
                    {
                        $model->to = true;
                    }
                }
                else
                {
                    throw new FeedbackException('Имя типа '.$type_name.' не поддерживается!');
                }
            }
            elseif($type_name === 'mailfromac')
            {
                $model = new Fbac();
                $model->name = $type_name;

                foreach(['domain','host','port','encryption'] as $field_name)
                {
                    if(array_key_exists($field_name, $defaults))
                    {
                        $model->$field_name = (string) $defaults[$field_name];
                    }
                    else
                    {
                        $model->$field_name = '';
                    }
                }
            }
            else
            {
                throw new FeedbackException('Имя типа '.$type_name.' не поддерживается!');
            }

            $model->save();

            $id = $model->id;
        }
        else
        {
            throw new FeedbackException('При инициализации передан тип с рангом отличным от блока и группы: '.$type->getRank().'!');
        }

        //Ссылки на внешние А типы потом дописать

        $Aref = new ARef($type, $id);
        //----------------------------------------------------------------------
        $owns = $type->getOwns();

        foreach($owns as $own_name => $own)
        {
            if(in_array($own_name, $self_fields))
            {
                continue;
            }

            $family = $own->getFieldTypeFamily();
            $mode = $own->getMode();

            if(array_key_exists($own_name, $defaults))
            {
                $value = $defaults[$own_name];
            }
            else
            {
                $value = null;
            }

            if($mode === TypeMode::MODE_B)
            {
                $initializer = $this->initMediator->getBInitializer($family);
                $initializer->init($Aref, $own, $value);
            }
            elseif($mode === TypeMode::MODE_C)
            {
                $initializer = $this->initMediator->getCInitializer($family);
                $initializer->init($Aref, $own, $value);
            }
        }

        DB::commit();
        //]]]

        return $Aref;
    }
727579
public function newEntity(array $data): EntityInterface {
		if (empty($this->entityType)) {
			throw new EntityFactoryException("Cannot produce entity without type.", EntityFactoryException::UNSET_ENTITY_TYPE);
		}
		
		return new $this->entityType($data);
	}
286095
function proto($new = null, $return_entity = false)
    {
        if (isset($new)){
            if ($new instanceof Entity){
                $this->_proto = $new;
                $new = $new->uri();
            }else{
                $this->_proto = null; // for reloading
            }
            if ($new != $this->_attributes['proto']){
                $this->change('proto', $new);
            }
        }
        if ($return_entity){
            if (!isset($this->_proto)){
                if (isset($this->_attributes['proto'])){
                    $this->_proto = Data::read($this->_attributes['proto']);
                }else{
                    $this->_proto = false;
                }
            }
            return $this->_proto;
        }
        return $this->_attributes['proto'];
    }
110571
public static function newEntityType($class, array $choices = [], array $options = []) {

        // Check the options.
        if (false === array_key_exists("empty", $options)) {
            $options["empty"] = false;
        }
        if (false === array_key_exists("translator", $options)) {
            $options["translator"] = null;
        }

        // Initialize the output.
        $output = [
            "class"        => $class,
            "choices"      => [],
            "choice_label" => function($entity) use ($options) {
                return FormRenderer::renderOption($entity, $options["translator"]);
            },
        ];

        // Add an empty choice.
        if (true === $options["empty"]) {
            $output["choices"][] = null;
        }

        // Add all choices.
        $output["choices"] = array_merge($output["choices"], $choices);

        return $output;
    }
61879
public function entitiesFrom(IEntitySet $entities) : ObjectArrayFieldBuilder
    {
        return (new ObjectArrayFieldBuilder($this
            ->type(new ArrayOfObjectIdsType(
                $entities,
                Field::element()->entityFrom($entities)->required()->build(),
                $loadAsObjects = true
            ))
        ))->containsNoDuplicates();
    }
524003
public function put(array $arr_docs)
    {
        $obj_request = new IndexDocumentRequest();
        $obj_params = $this->prepareRequestParams($obj_request);

        // Other index specs: consistency, mode, name, namespace, source, version
        $obj_mapper = new Mapper();
        foreach($arr_docs as $obj_doc) {
            $obj_mapper->toGoogle($obj_doc, $obj_params->addDocument());
        }
        $this->execute('IndexDocument', $obj_request, new IndexDocumentResponse());
    }
224960
protected function createEntities(array $rows, $entityClass = null, $table = null)
    {
        if ($table === null) {
            $table = $this->getTable();
        }
        $entities = [];
        $collection = Result::createInstance($rows, $table, $this->connection, $this->mapper);
        $primaryKey = $this->mapper->getPrimaryKey($this->getTable());
        if ($entityClass !== null) {
            foreach ($rows as $dibiRow) {
                $entity = $this->entityFactory->createEntity(
                    $entityClass,
                    $collection->getRow($dibiRow->$primaryKey)
                );
                $entity->makeAlive($this->entityFactory);
                $entities[$dibiRow->$primaryKey] = $entity;
            }
        } else {
            foreach ($rows as $dibiRow) {
                $row = $collection->getRow($dibiRow->$primaryKey);
                $entityClass = $this->mapper->getEntityClass($this->getTable(), $row);
                $entity = $this->entityFactory->createEntity($entityClass, $row);
                $entity->makeAlive($this->entityFactory);
                $entities[$dibiRow->$primaryKey] = $entity;
            }
        }
        return $this->entityFactory->createCollection($entities);
    }
1045925
private function updateRegistries($entities, $from)
    {
        if (count($entities) >= 0) {
            for ($j = $from; $j >= 0; $j--) {
                /** @var RegistryInterface $registry */
                $registry = $this->registries[ $j ];
                /** @var AbstractEntity $entity */
                foreach ($entities as $entity) {
                    $registry->add($entity->getId(), $entity);
                }
            }
        }
    }
964482
public function deleteMulti(array $arr_entities)
    {
        $obj_mapper = $this->createMapper();
        $obj_request = $this->setupCommit();
        $obj_mutation = $obj_request->mutableDeprecatedMutation();
        foreach($arr_entities as $obj_gds_entity) {
            $this->applyNamespace(
                $obj_mapper->configureGoogleKey(
                    $obj_mutation->addDelete(), $obj_gds_entity
                )
            );
        }
        $this->execute('Commit', $obj_request, new CommitResponse());
        $this->obj_schema = null;
        return TRUE; // really?
    }
1361003
public function createDocument(array $arr_data = null)
    {
        $obj_doc = new Document($this);
        if(null !== $arr_data) {
            foreach ($arr_data as $str_field => $mix_value) {
                $obj_doc->__set($str_field, $mix_value);
            }
        }
        return $obj_doc;
    }
1232064
private function load(array $entities, callable $queryBuilderCallback = null)
    {
        foreach ($entities as $key => $entity) {
            $hash = spl_object_hash($entity);

            if (!empty($queryBuilderCallback)) {
                /** @var callable|object $queryBuilderCallback */
                $hash .= spl_object_hash($queryBuilderCallback);
            }
            if (isset($this->processedHashes[$hash])) {
                unset($entities[$key]);

                continue;
            }

            $this->processedHashes[$hash] = true;

            $entityClass = ClassUtils::getClass($entity);

            if (!$this->customObjectsLoadable($entityClass)) {
                $message = sprintf(
                    'Class "%s" must be annotated with "%s" annotation in order to load custom objects.',
                    $entityClass,
                    CustomObject::class
                );

                throw new CustomObjectException($message);
            }
        }

        $customEntitiesMap = $this->buildCustomEntitiesMap($entities);

        $queriesMap = $this->buildQueriesMap($customEntitiesMap);

        $customEntities = $this->fetchCustomEntities($queriesMap, $queryBuilderCallback);

        $this->setCustomEntities($entities, $customEntities, $customEntitiesMap);
    }
155396
protected function mapAutoIDs(array $arr_auto_id_requested)
    {
        if (!empty($arr_auto_id_requested)) {
            $arr_auto_ids = $this->extractAutoIDs();
            if(count($arr_auto_id_requested) === count($arr_auto_ids)) {
                foreach ($arr_auto_id_requested as $int_idx => $obj_gds_entity) {
                    $obj_gds_entity->setKeyId($arr_auto_ids[$int_idx]);
                }
            } else {
                throw new \Exception("Mismatch count of requested & returned Auto IDs");
            }
        }
    }
1221386
public function load($entities, $depth = 1)
    {
        if (!\is_array($entities) && !$entities instanceof \Traversable) {
            throw new \InvalidArgumentException(self::E_MSG);
        }

        $entitiesByValueClassByIds = $this->sortEntitiesByValueClass($entities);
        foreach ($entitiesByValueClassByIds as $valueClass => $entitiesById) {
            $this->loadEntityValues($valueClass, $entitiesById);
        }

        $this->loadRelatedEntities($entities, $depth);
    }
194519
protected function initSources(array $sources)
    {
        foreach ($sources as $source) {
            $this->sources[] = new EntitySource($this, $source);
        }
    }
1220839
public function createEntity(string $entity_id, array $parents)
    {
        $entity = new Entity($this, $entity_id, $parents);
        return $entity;
    }