ApiPlatform\SchemaGenerator\TypesGenerator::generate PHP Method

generate() public method

Generates files.
public generate ( array $config )
$config array
    public function generate(array $config)
    {
        $baseClass = ['constants' => [], 'fields' => [], 'uses' => [], 'hasConstructor' => false, 'parentHasConstructor' => false, 'hasChild' => false, 'abstract' => false];
        $typesToGenerate = [];
        if (empty($config['types'])) {
            foreach ($this->graphs as $graph) {
                $typesToGenerate = $graph->allOfType('rdfs:Class');
            }
        } else {
            foreach ($config['types'] as $typeName => $typeConfig) {
                $resource = null;
                foreach ($this->graphs as $graph) {
                    $resources = $graph->resources();
                    if (isset($resources[$typeConfig['vocabularyNamespace'] . $typeName])) {
                        $resource = $graph->resource($typeConfig['vocabularyNamespace'] . $typeName, 'rdfs:Class');
                        break;
                    }
                }
                if ($resource) {
                    $typesToGenerate[$typeName] = $resource;
                } else {
                    $this->logger->warning('Type "{typeName}" cannot be found. Using "{guessFrom}" type to generate entity.', ['typeName' => $typeName, 'guessFrom' => $typeConfig['guessFrom']]);
                    $type = $graph->resource($typeConfig['vocabularyNamespace'] . $typeConfig['guessFrom'], 'rdfs:Class');
                    $typesToGenerate[$typeName] = $type;
                }
            }
        }
        $classes = [];
        $propertiesMap = $this->createPropertiesMap($typesToGenerate);
        foreach ($typesToGenerate as $typeName => $type) {
            $typeName = is_string($typeName) ? $typeName : $type->localName();
            $typeConfig = isset($config['types'][$typeName]) ? $config['types'][$typeName] : null;
            $class = $baseClass;
            $comment = $type->get('rdfs:comment');
            $class['name'] = $typeName;
            $class['label'] = $comment ? $comment->getValue() : '';
            $class['resource'] = $type;
            $class['config'] = $typeConfig;
            $class['isEnum'] = $this->isEnum($type);
            if ($class['isEnum']) {
                $class['namespace'] = isset($typeConfig['namespace']) ? $typeConfig['namespace'] : $config['namespaces']['enum'];
                $class['parent'] = self::ENUM_EXTENDS;
                $class['uses'][] = self::ENUM_USE;
                // Constants
                foreach ($this->graphs as $graph) {
                    foreach ($graph->allOfType($type->getUri()) as $instance) {
                        $class['constants'][$instance->localName()] = ['name' => strtoupper(substr(preg_replace('/([A-Z])/', '_$1', $instance->localName()), 1)), 'resource' => $instance, 'value' => $instance->getUri()];
                    }
                }
            } else {
                // Entities
                $class['namespace'] = isset($typeConfig['namespaces']['class']) ? $typeConfig['namespaces']['class'] : $config['namespaces']['entity'];
                // Parent
                $class['parent'] = isset($typeConfig['parent']) ? $typeConfig['parent'] : null;
                if (null === $class['parent']) {
                    $numberOfSupertypes = count($type->all('rdfs:subClassOf'));
                    if ($numberOfSupertypes > 1) {
                        $this->logger->warning(sprintf('The type "%s" has several supertypes. Using the first one.', $type->localName()));
                    }
                    $class['parent'] = $numberOfSupertypes ? $type->all('rdfs:subClassOf')[0]->localName() : false;
                }
                if (isset($class['parent']) && isset($config['types'][$class['parent']]['namespaces']['class'])) {
                    $parentNamespace = $config['types'][$class['parent']]['namespaces']['class'];
                    if ($parentNamespace !== $class['namespace']) {
                        $class['uses'][] = $parentNamespace . '\\' . $class['parent'];
                    }
                }
                // Embeddable
                $class['embeddable'] = isset($typeConfig['embeddable']) ? $typeConfig['embeddable'] : false;
                if (!empty($config['types']) && $class['parent'] && !isset($config['types'][$class['parent']])) {
                    $this->logger->error(sprintf('The type "%s" (parent of "%s") doesn\'t exist', $class['parent'], $type->localName()));
                }
                // Interfaces
                if ($config['useInterface']) {
                    $class['interfaceNamespace'] = isset($typeConfig['namespaces']['interface']) && $typeConfig['namespaces']['interface'] ? $typeConfig['namespaces']['interface'] : $config['namespaces']['interface'];
                    $class['interfaceName'] = sprintf('%sInterface', $typeName);
                }
            }
            // Fields
            if (!$typeConfig['allProperties'] && isset($typeConfig['properties']) && is_array($typeConfig['properties'])) {
                foreach ($typeConfig['properties'] as $key => $value) {
                    foreach ($propertiesMap[$type->getUri()] as $property) {
                        if ($key !== $property->localName()) {
                            continue;
                        }
                        $class = $this->generateField($config, $class, $type, $typeName, $property->localName(), $property);
                        continue 2;
                    }
                    // Add custom fields (non schema.org)
                    $this->logger->info(sprintf('The property "%s" (type "%s") is a custom property.', $key, $type->localName()));
                    $class = $this->generateField($config, $class, $type, $typeName, $key);
                }
            } else {
                // All properties
                foreach ($propertiesMap[$type->getUri()] as $property) {
                    $class = $this->generateField($config, $class, $type, $typeName, $property->localName(), $property);
                }
            }
            $classes[$typeName] = $class;
        }
        // Second pass
        foreach ($classes as &$class) {
            if ($class['parent'] && isset($classes[$class['parent']])) {
                $classes[$class['parent']]['hasChild'] = true;
                $class['parentHasConstructor'] = $classes[$class['parent']]['hasConstructor'];
            }
            foreach ($class['fields'] as &$field) {
                $field['isEnum'] = isset($classes[$field['range']]) && $classes[$field['range']]['isEnum'];
            }
        }
        // Third pass
        foreach ($classes as &$class) {
            if (isset($config['types'][$class['name']]['abstract']) && null !== $config['types'][$class['name']]['abstract']) {
                $class['abstract'] = $config['types'][$class['name']]['abstract'];
            } else {
                $class['abstract'] = $class['hasChild'];
            }
            // When including all properties, ignore properties already set on parent
            if (isset($config['types'][$class['name']]['allProperties']) && $config['types'][$class['name']]['allProperties'] && isset($classes[$class['parent']])) {
                $type = $class['resource'];
                foreach ($propertiesMap[$type->getUri()] as $property) {
                    if (!isset($class['fields'][$property->localName()])) {
                        continue;
                    }
                    $parentConfig = isset($config['types'][$class['parent']]) ? $config['types'][$class['parent']] : null;
                    $parentClass = $classes[$class['parent']];
                    while ($parentClass) {
                        if (!isset($parentConfig['properties']) || !is_array($parentConfig['properties'])) {
                            // Unset implicit property
                            $parentType = $parentClass['resource'];
                            if (in_array($property, $propertiesMap[$parentType->getUri()])) {
                                unset($class['fields'][$property->localName()]);
                                continue 2;
                            }
                        } else {
                            // Unset explicit property
                            if (array_key_exists($property->localName(), $parentConfig['properties'])) {
                                unset($class['fields'][$property->localName()]);
                                continue 2;
                            }
                        }
                        $parentConfig = $parentClass['parent'] ? isset($config['types'][$parentClass['parent']]) ? $config['types'][$parentClass['parent']] : null : null;
                        $parentClass = $parentClass['parent'] ? $classes[$parentClass['parent']] : null;
                    }
                }
            }
        }
        // Generate ID
        if ($config['generateId']) {
            foreach ($classes as &$class) {
                if (!$class['hasChild'] && !$class['isEnum'] && !$class['embeddable']) {
                    $class['fields'] = ['id' => ['name' => 'id', 'resource' => null, 'range' => 'Integer', 'cardinality' => CardinalitiesExtractor::CARDINALITY_1_1, 'ormColumn' => null, 'isArray' => false, 'isNullable' => false, 'isUnique' => false, 'isCustom' => true, 'isEnum' => false, 'isId' => true]] + $class['fields'];
                }
            }
        }
        // Initialize annotation generators
        $annotationGenerators = [];
        foreach ($config['annotationGenerators'] as $annotationGenerator) {
            $generator = new $annotationGenerator($this->logger, $this->graphs, $this->cardinalities, $config, $classes);
            $annotationGenerators[] = $generator;
        }
        $interfaceMappings = [];
        $generatedFiles = [];
        foreach ($classes as $className => &$class) {
            $class['uses'] = $this->generateClassUses($annotationGenerators, $classes, $className);
            $class['annotations'] = $this->generateClassAnnotations($annotationGenerators, $className);
            if (false === isset($typesToGenerate[$className])) {
                $class['interfaceAnnotations'] = $this->generateInterfaceAnnotations($annotationGenerators, $className);
            }
            foreach ($class['constants'] as $constantName => $constant) {
                $class['constants'][$constantName]['annotations'] = $this->generateConstantAnnotations($annotationGenerators, $className, $constantName);
            }
            foreach ($class['fields'] as $fieldName => &$field) {
                $typeHint = false;
                if ($this->isDateTime($field['range'])) {
                    $typeHint = '\\DateTime';
                } elseif (!($this->isDatatype($field['range']) || $field['isEnum'])) {
                    if (isset($classes[$field['range']]['interfaceName'])) {
                        $typeHint = $classes[$field['range']]['interfaceName'];
                    } else {
                        $typeHint = $classes[$field['range']]['name'];
                    }
                }
                $field['typeHint'] = $typeHint;
                $field['annotations'] = $this->generateFieldAnnotations($annotationGenerators, $className, $fieldName);
                $field['getterAnnotations'] = $this->generateGetterAnnotations($annotationGenerators, $className, $fieldName);
                if ($field['isArray']) {
                    $field['adderAnnotations'] = $this->generateAdderAnnotations($annotationGenerators, $className, $fieldName);
                    $field['removerAnnotations'] = $this->generateRemoverAnnotations($annotationGenerators, $className, $fieldName);
                } else {
                    $field['setterAnnotations'] = $this->generateSetterAnnotations($annotationGenerators, $className, $fieldName);
                }
            }
            $classDir = $this->namespaceToDir($config, $class['namespace']);
            if (!file_exists($classDir)) {
                mkdir($classDir, 0777, true);
            }
            $path = sprintf('%s%s.php', $classDir, $className);
            $generatedFiles[] = $path;
            file_put_contents($path, $this->twig->render('class.php.twig', ['config' => $config, 'class' => $class]));
            if (isset($class['interfaceNamespace'])) {
                $interfaceDir = $this->namespaceToDir($config, $class['interfaceNamespace']);
                if (!file_exists($interfaceDir)) {
                    mkdir($interfaceDir, 0777, true);
                }
                $path = sprintf('%s%s.php', $interfaceDir, $class['interfaceName']);
                $generatedFiles[] = $path;
                file_put_contents($path, $this->twig->render('interface.php.twig', ['config' => $config, 'class' => $class]));
                if ($config['doctrine']['resolveTargetEntityConfigPath'] && !$class['abstract']) {
                    $interfaceMappings[$class['interfaceNamespace'] . '\\' . $class['interfaceName']] = $class['namespace'] . '\\' . $className;
                }
            }
        }
        if (!empty($interfaceMappings) && $config['doctrine']['resolveTargetEntityConfigPath']) {
            $file = $config['output'] . '/' . $config['doctrine']['resolveTargetEntityConfigPath'];
            $dir = dirname($file);
            if (!file_exists($dir)) {
                mkdir($dir, 0777, true);
            }
            file_put_contents($file, $this->twig->render('doctrine.xml.twig', ['mappings' => $interfaceMappings]));
            $generatedFiles[] = $file;
        }
        $this->fixCs($generatedFiles);
    }

Usage Example

 public function testGenerate()
 {
     $twigProphecy = $this->prophesize('Twig_Environment');
     $classes = $this->getClasses();
     foreach ($classes as $class) {
         $twigProphecy->render('class.php.twig', Argument::that($this->getContextMatcher($class)))->willReturn()->shouldBeCalled();
     }
     $twigProphecy->render('class.php.twig', Argument::type('array'))->willReturn();
     $twig = $twigProphecy->reveal();
     $cardinalitiesExtractorProphecy = $this->prophesize('ApiPlatform\\SchemaGenerator\\CardinalitiesExtractor');
     $cardinalities = $this->getCardinalities();
     $cardinalitiesExtractorProphecy->extract()->willReturn($cardinalities)->shouldBeCalled();
     $cardinalitiesExtractor = $cardinalitiesExtractorProphecy->reveal();
     $goodRelationsBridgeProphecy = $this->prophesize('ApiPlatform\\SchemaGenerator\\GoodRelationsBridge');
     $goodRelationsBridge = $goodRelationsBridgeProphecy->reveal();
     $typesGenerator = new TypesGenerator($twig, new NullLogger(), $this->getGraphs(), $cardinalitiesExtractor, $goodRelationsBridge);
     $typesGenerator->generate($this->getConfig());
 }
All Usage Examples Of ApiPlatform\SchemaGenerator\TypesGenerator::generate