blob: f13eddb6237ccb59b9e1460e4825d69d72c18965 [file] [log] [blame]
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Apache\Ignite\Internal\Binary;
use Apache\Ignite\Type\ComplexObjectType;
class BinaryTypeBuilder
{
private $type;
private $schema;
private $fromStorage;
private function __construct()
{
$this->type = null;
$this->schema = null;
$this->fromStorage = false;
}
public static function fromTypeName(string $typeName): BinaryTypeBuilder
{
$result = new BinaryTypeBuilder();
$result->init($typeName);
return $result;
}
public static function fromTypeId(BinaryCommunicator $communicator, int $typeId, ?int $schemaId): BinaryTypeBuilder
{
$result = new BinaryTypeBuilder();
$type = $communicator->getTypeStorage()->getType($typeId, $schemaId);
if ($type) {
$result->type = $type;
if ($schemaId !== null) {
$result->schema = $type->getSchema($schemaId);
if (!$result->schema) {
BinaryUtils::serializationError(
false,
sprintf('schema id "%d" specified for complex object of type "%s" not found', $schemaId, $type->getName()));
}
$result->fromStorage = true;
} else {
$result->schema = new BinarySchema();
}
return $result;
}
$result->init(null);
$result->getType()->setId($typeId);
return $result;
}
public static function fromObject(object $object, ComplexObjectType $complexObjectType = null): BinaryTypeBuilder
{
if ($complexObjectType) {
return BinaryTypeBuilder::fromComplexObjectType($complexObjectType, $object);
} else {
$result = new BinaryTypeBuilder();
$result->fromComplexObject(new ComplexObjectType(), $object);
return $result;
}
}
public static function fromComplexObjectType(ComplexObjectType $complexObjectType, object $object): BinaryTypeBuilder
{
$result = new BinaryTypeBuilder();
$typeInfo = BinaryTypeStorage::getByComplexObjectType($complexObjectType);
if ($typeInfo) {
$result->type = $typeInfo[0];
$result->schema = $typeInfo[1];
$result->fromStorage = true;
} else {
$result->fromComplexObject($complexObjectType, $object);
BinaryTypeStorage::setByComplexObjectType($complexObjectType, $result->type, $result->schema);
}
return $result;
}
public static function calcTypeName(ComplexObjectType $complexObjectType, object $object): string
{
$typeName = $complexObjectType->getIgniteTypeName();
if (!$typeName) {
$typeName = $object ? get_class($object) : null;
}
return $typeName;
}
public function getType(): BinaryType
{
return $this->type;
}
public function getTypeId(): int
{
return $this->type->getId();
}
public function getTypeName(): string
{
return $this->type->getName();
}
public function getSchema(): BinarySchema
{
return $this->schema;
}
public function getSchemaId(): int
{
return $this->schema->getId();
}
public function getFields(): array
{
return $this->type->getFields();
}
public function getField(int $fieldId): ?BinaryField
{
return $this->type->getField($fieldId);
}
public function setField(string $fieldName, int $fieldTypeCode = 0): void
{
$fieldId = BinaryField::calculateId($fieldName);
if (!$this->type->hasField($fieldId) || !$this->schema->hasField($fieldId) ||
$this->type->getField($fieldId)->getTypeCode() !== $fieldTypeCode) {
$this->beforeModify();
$this->type->setField(new BinaryField($fieldName, $fieldTypeCode));
$this->schema->addField($fieldId);
}
}
public function removeField(string $fieldName): void
{
$fieldId = BinaryField::calculateId($fieldName);
if ($this->type->hasField($fieldId)) {
$this->beforeModify();
$this->type->removeField($fieldId);
$this->schema->removeField($fieldId);
}
}
public function finalize(BinaryCommunicator $communicator): void
{
$this->schema->finalize();
$communicator->getTypeStorage()->addType($this->type, $this->schema);
}
private function fromComplexObject(ComplexObjectType $complexObjectType, object $object): void
{
$typeName = BinaryTypeBuilder::calcTypeName($complexObjectType, $object);
$this->init($typeName);
$this->setFields($complexObjectType, $object);
}
private function init(?string $typeName): void
{
$this->type = new BinaryType($typeName);
$this->schema = new BinarySchema();
}
private function beforeModify(): void
{
if ($this->fromStorage) {
$this->type = $this->type->cloneType();
$this->schema = $this->schema->cloneSchema();
$this->fromStorage = false;
}
}
private function setFields(ComplexObjectType $complexObjectType, object $object): void
{
try {
$reflect = new \ReflectionClass($object);
$properties = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC);
foreach ($properties as $property) {
if ($property->isStatic()) {
continue;
}
$fieldName = $property->getName();
$fieldType = $complexObjectType->getFieldType($fieldName);
if (!$fieldType) {
$fieldValue = $property->getValue($object);
$fieldType = BinaryUtils::calcObjectType($fieldValue);
}
$this->setField($fieldName, BinaryUtils::getTypeCode($fieldType));
}
} catch (\ReflectionException $e) {
BinaryUtils::serializationError(true, sprintf('class "%s" does not exist', get_class($object)));
}
}
}