/**
  * Factory method to create type instances.
  * AbstractType instances are implemented as flyweights.
  *
  * @param $value
  *
  * @return DataValueInterface
  */
 public function getDataValueFromValue($value)
 {
     if (null === $value) {
         return new NullValue();
     }
     $typeName = $this->typeFactory->getTypeFromValue($value);
     return $this->createValue($typeName, $value);
 }
 private function transformTypeToValidTingType($type)
 {
     if ('enum' === $type) {
         return 'string';
     }
     $datatype = $this->typeFactory->getTypeFromName($type);
     $map = [ObjectType::class => 'string', ArrayType::class => 'json', BooleanType::class => 'bool', DateTimeType::class => 'datetime', DateType::class => 'datetime', FloatType::class => 'double', IntegerType::class => 'int', JsonArrayType::class => 'json', StringType::class => 'string', TimeType::class => 'datetime'];
     return $map[get_class($datatype)];
 }
 private function buildEntitiesPropertiesNode()
 {
     $entitiesPropertiesNode = new ArrayNodeDefinition('properties');
     $prototype = $entitiesPropertiesNode->info('List of properties of entity')->prototype('array');
     foreach ($this->treeConfigurators as $configurator) {
         foreach ((array) $configurator->appendEntitiesPropertiesNode() as $node) {
             $prototype->append($node);
         }
     }
     $prototype->children()->scalarNode('type')->info('type of data, standard type of other entity name')->example('DateTime')->cannotBeEmpty()->beforeNormalization()->always(function ($v) {
         return strtolower($v);
     })->end()->validate()->ifTrue(function ($v) {
         return !$this->typeFactory->isValidType($v);
     })->thenInvalid('Invalid Type %s')->end()->end()->scalarNode('cardinality')->info('type of cardinality OneToMany, ManyToMany')->example('(0..1)')->cannotBeEmpty()->end()->scalarNode('accessorPrefix')->info('Prefix used has accessor method : prefixPropertieName')->example('is, has, get')->defaultValue('get')->end()->scalarNode('enum')->info('Name of target enum')->cannotBeEmpty()->end()->scalarNode('entity')->info('name of target entity')->example('DateTime')->cannotBeEmpty()->end()->scalarNode('inverse')->info('define oposite property in cas of relation')->example('MyEntity::propertieName')->cannotBeEmpty()->end()->booleanNode('nullable')->info('Is this propertie is nullable?')->defaultFalse()->end()->booleanNode('primary')->info('Is this propertie is primary key ?')->defaultFalse()->end()->booleanNode('autoincrement')->info('Is this propertie is auto incremented ?')->defaultFalse()->end()->booleanNode('unique')->info('Is this propertie is unique?')->defaultFalse()->end()->variableNode('default')->info('Default value of propertie')->end()->integerNode('length')->info('Max length for string type')->min(0)->end()->integerNode('precision')->info('Number of decimal for float type')->min(1)->max(15)->end();
     $entitiesPropertiesNode->end();
     return $entitiesPropertiesNode;
 }
 /**
  * @param $propertyName
  * @param $propertyConfig
  * @return PropertyDefinition
  * @throws \Exception
  */
 private function createProperty($propertyName, $propertyConfig)
 {
     $defaultValue = null;
     switch ($propertyConfig['type']) {
         case "relation":
             if (false === array_key_exists('entity', $propertyConfig)) {
                 throw new \Exception(sprintf('property[type: Relation] %s must define "entity" key', $propertyName));
             }
             $fqcn = $this->createEntityFqcn($this->configuration, $propertyConfig['entity']);
             if (true === array_key_exists('inverse', $propertyConfig)) {
                 //Inversed side
                 if (false === array_key_exists($propertyConfig['entity'], $this->configuration['entities'])) {
                     throw new \Exception(sprintf('property[type: Relation] %s is inversed by %s but this entity does not exist ', $propertyName, $propertyConfig['entity']));
                 }
                 if (false === array_key_exists($propertyConfig['inverse'], $this->configuration['entities'][$propertyConfig['entity']]['properties'])) {
                     throw new \Exception(sprintf('property %s as %s for inverse property, but this property does not exist ', $propertyName, $propertyConfig['inverse']));
                 }
                 $inversedProperty = $this->configuration['entities'][$propertyConfig['entity']]['properties'][$propertyConfig['inverse']];
                 if (false === array_key_exists('cardinality', $inversedProperty)) {
                     throw new \Exception(sprintf('property[type: Relation] %s must define "cardinality" key', $propertyConfig['entity']));
                 }
                 /** @var Cardinality $cardinality */
                 $cardinality = new Cardinality($inversedProperty['cardinality']);
                 $type = new ObjectType($fqcn);
                 if (true === $cardinality->hasSourceMany()) {
                     $type = new ArrayType($type);
                 }
             } else {
                 //Relation Side
                 $type = new ObjectType($fqcn);
                 if (false === array_key_exists('cardinality', $propertyConfig)) {
                     throw new \Exception(sprintf('property[type: Relation] %s must define "cardinality" key', $propertyName));
                 }
                 /** @var Cardinality $cardinality */
                 $cardinality = new Cardinality($propertyConfig['cardinality']);
                 if (true === $cardinality->hasTargetMany()) {
                     $type = new ArrayType($type);
                 }
             }
             break;
         case "enum":
             $fqcn = $this->createEnumFqcn($this->configuration, $propertyConfig['enum']);
             $type = new ObjectType($fqcn);
             if (true === array_key_exists('default', $propertyConfig)) {
                 $defaultValue = new ObjectValue($fqcn, [new StringValue($propertyConfig['default'])]);
             }
             break;
         case "enum[]":
             $fqcn = $this->createEnumFqcn($this->configuration, $propertyConfig['enum']);
             $type = new ArrayType(new ObjectType($fqcn));
             $defaultValue = new ArrayValue([]);
             break;
         default:
             $type = $this->typeFactory->getTypeFromName($propertyConfig['type']);
             if (true === array_key_exists('default', $propertyConfig)) {
                 $defaultValue = $this->valueFactory->createValue($type, $propertyConfig['default']);
             }
     }
     $name = new PhpVariableName($propertyName);
     $property = new PropertyDefinition($propertyName, $propertyConfig, $type, $name, $defaultValue);
     return $property;
 }