/** * @param string $ramlFile */ public function generateRest($ramlFile, Local $directoryOutput) { $parser = new Parser(); try { /* * file di routing symfony * @var array */ $routing = []; /* * Mappa delle proprieta dei controller da generare * @var array */ $mappaClassDef = []; $this->apiDef = $parser->parse($ramlFile); $this->logger->info('Title: ' . $this->apiDef->getTitle()); $baseUrl = $this->apiDef->getBaseUrl(); $parametriBaseUrl = $this->apiDef->getBaseUriParameters(); /** @var \Raml\BaseUriParameter $definition */ foreach ($parametriBaseUrl as $varName => $definition) { if (!array_key_exists($varName, $this->mapExternalInfo)) { $this->error('Missing: ' . $varName . ' -> ' . $definition->getDescription()); $this->mapExternalInfo[$varName] = 'undefined'; } $baseUrl = str_replace($varName, $this->mapExternalInfo[$varName], $baseUrl); } $this->info('BaseUrl ' . $baseUrl); //corrisponde a host: "{subdomain}.example.com" dentro routing.yml $enabledProtocols = $this->apiDef->getProtocols(); //serve per fare controlli su http/https -> schemes: [https] dentro routing.yml $infoSecuritySchema = $this->apiDef->getSecuredBy(); // descrive i vari security schema usati nelle varie risorse /* @var: \Raml\Resource[] */ $resources = $this->apiDef->getResources(); $namespace = $this->bundleName . '\\Controller'; /** @var: \Raml\Resource $resource */ foreach ($resources as $resource) { $displayName = $resource->getDisplayName(); $this->info('Controller per path: ' . $displayName); $names = explode('/', $displayName); preg_match_all("/(\\/{[a-zA-Z]+}(\\/)?)+/i", $displayName, $methodParam); array_walk($names, [$this, 'removeGraph']); $className = implode('', $names); $methods = $resource->getMethods(); if (count($methods) > 0) { /** @var \Raml\Method $method */ foreach ($methods as $method) { $controllerName = ucfirst($className); // Creo $appBundle / $workspace Controller . php $this->info('Genera: ' . $namespace . $controllerName . 'Controller'); $controllerProperties = []; $controllerProperties['name'] = $controllerName . 'Controller'; $controllerProperties['namespace'] = $namespace; $controllerProperties['extend'] = 'Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller'; $methodListParams = implode(',', $methodParam[0]); $type = strtolower($method->getType()); $methodCallName = $type . $controllerName; $actionName = $methodCallName . 'Action'; $this->info('Call Method: ' . $actionName . '(' . $methodListParams . ')'); $controllerProperties['methods'] = []; $controllerProperties['methods'][$actionName] = []; $controllerProperties['methods'][$actionName]['params'] = []; $description = $method->getDescription(); $this->info('Description: ' . $description); $entryName = strtolower($className) . '_' . $type; $routing[$entryName]['path'] = $displayName; $routing[$entryName]['defaults']['_controller'] = $this->bundleName . ':' . $controllerName . ':' . $methodCallName; $routing[$entryName]['host'] = $baseUrl; $routing[$entryName]['methods'] = []; $routing[$entryName]['methods'][] = strtoupper($type); $routing[$entryName]['schemas'] = $enabledProtocols; $routing[$entryName]['requirements'] = []; $routing[$entryName]['requirements'][] = 'FIXME'; $mappaClassDef[$controllerName . 'Controller'] = $controllerProperties; } //fine methods } /* @var \Raml\Resource $subResources */ $subResources = $resource->getResources(); foreach ($subResources as $subResource) { //$this->analyzeResource($subResource, $directoryOutput); //// SAMPLE: // /Workspace GET => Workspace/GetWorkspace.php // /Workspace POST => Workspace/POSTWorkspace.php // /Workspace/{id} GET => Workspace/GetWorkspaceById.php } } //fine reousrces $indent = 4; $inline = 2; $yaml = new Dumper($indent); $this->currentFile = $yaml->dump($routing, $inline, 0, 0); $this->_createFileOnDir($directoryOutput, $this->bundleName . '/Resources/config/routing.yml'); foreach ($mappaClassDef as $className => $controllerProp) { $this->info('Devo creare ' . $className); $gClassgen = new ClassGenerator($namespace, $className); $gClassgen->setLogger($this->logger); $config = new ClassConfig(); $typesReferenceArray = []; $typesDescArray = []; $gClassgen->generateClassType($controllerProp, $typesReferenceArray, $typesDescArray, $config); $gClassgen->createFileOnDir($directoryOutput); } $this->info('Scrittura su ' . $directoryOutput); } catch (InvalidJsonException $e) { $this->error('[' . $e->getErrorCode() . '] ' . $e->getMessage()); $this->error($e->getTraceAsString()); } catch (RamlParserException $e) { $this->error('[' . $e->getErrorCode() . '] ' . $e->getMessage()); } }
public function testFirstClassMethodGenerator() { $namespace = 'TestNamespace'; $className = 'FirstMethodClass'; $gClassgen = new ClassGenerator($namespace, $className); $gClassgen->setLogger($this->logger); $config = new ClassConfig(); $properties = ['extend' => 'ExtendClass', 'implements' => 'IClass', 'methods' => ['methodName' => ['params' => ['prova' => ['primitive' => 'int', 'description' => 'session unique identifier'], 'prova2' => ['primitive' => 'string', 'description' => 'campo generico']]]]]; $typesReferenceArray = []; $typesDescArray = []; $gClassgen->generateClassType($properties, $typesReferenceArray, $typesDescArray, $config); $resourcesDir = __DIR__ . '/../Resources/php'; $this->compareFileGenerated($resourcesDir, $namespace, $className, $gClassgen); }
/** * [generate description]. * * @param Local $directoryOutput directory where write generated class */ public function generate(Local $directoryOutput) { //$is_constructor_enable = true; //$ddd_is_root_aggregate = false; $specListClasses = $this->rym->getClassesDefinition(); foreach ($specListClasses as $className => $properties) { $this->info('Generate class', ['class' => $className]); //, 'properties' => $properties if (!array_key_exists('ddd', $properties)) { $this->error('missing ddd section into yml for class', ['class' => $className]); $this->errors[] = 'missing ddd section into yml for class ' . $className; $this->info('force ' . $className . ' to type class'); $properties['ddd'] = []; $properties['ddd']['type'] = 'class'; } $namespace = ''; if (array_key_exists('namespace', $properties)) { $namespace = $properties['namespace']; } $classComments = 'No comment found on ddd model'; if (array_key_exists('description', $properties)) { $classComments = $properties['description']; $this->info('Found description :' . $classComments); } //FIXME: switch with $dddType as key $generated = false; $dddType = $properties['ddd']['type']; if (in_array($dddType, ['interface'])) { $g = new ClassGenerator($namespace, $className, $classComments); $g->setLogger($this->logger); $config = new ClassConfig(); $config->isInterface = true; $g->generateClassType($properties, $this->modelClass, $this->modelComments, $config); $g->createFileOnDir($directoryOutput); $generated = true; //FIXME: use $g for determinate! -> take error from generator if ($generated) { $this->fieldsClass[$namespace . '\\' . $className] = $properties['fields']; //ONLY IF VALID!!! } // DOMANDA: perche' non passarle tutte?? // if (array_key_exists('fields', $properties)) { // $types_field[$className] = $properties['fields']; // } // $this->generateClassType($fileInterface, $interface, $properties, $types_reference, $types_description, false, true, true, false, false, $filesystem, $io); } // NOTE: class aren't ddd type, we haven't section on ddd definition if (in_array($dddType, ['class'])) { $g = new ClassGenerator($namespace, $className, $classComments); $g->setLogger($this->logger); $config = new ClassConfig(); $config->isInterface = false; $config->haveConstructor = true; $g->generateClassType($properties, $this->modelClass, $this->modelComments, $config); $g->createFileOnDir($directoryOutput); $generated = true; //FIXME: use $g for determinate! -> take error from generator if ($generated) { $this->fieldsClass[$namespace . '\\' . $className] = $properties['fields']; //ONLY IF VALID!!! } // DOMANDA: perche' non passarle tutte?? // if (array_key_exists('fields', $properties)) { // $types_field[$className] = $properties['fields']; // } // $this->generateClassType($fileInterface, $interface, $properties, $types_reference, $types_description, false, true, true, false, false, $filesystem, $io); } if (in_array($dddType, ['events'])) { //FIXME: impossible! events exist in relation on aggregateRoot $this->error('events exist in relation on aggregateRoot', ['class' => $className]); $this->errors[] = 'events exist in relation on aggregateRoot, event class ' . $className . ' cannot exist!'; } if (!$generated) { $dddDefinition = $this->rym->getDomainDefinitionAttributes($dddType); if (is_null($dddDefinition)) { $this->error('Missing ddd reference for : ' . $dddType . ' into ' . $className, ['class' => $className]); $this->errors[] = 'Missing ddd reference for : ' . $dddType . ' into ' . $className; } else { if (array_key_exists('package', $dddDefinition)) { $namespace = $dddDefinition['package']; } if (empty($namespace)) { $this->error('Missing namespace', ['class' => $className]); $this->errors[] = 'Missing namespace for ' . $className; } $createGetter = false; $createSetter = false; if (array_key_exists('getter', $dddDefinition)) { $createGetter = $dddDefinition['getter']; } if (array_key_exists('setter', $dddDefinition)) { $createSetter = $dddDefinition['setter']; } $isRootAggregate = $dddType == 'aggregate' && isset($properties['ddd']['root']) && boolval($properties['ddd']['root']) ? true : false; $this->info('Method required', ['class' => $className, 'getter' => $createGetter, 'setter' => $createSetter, 'aggregateRoot' => $isRootAggregate]); if (array_key_exists('extend', $dddDefinition)) { $dddExtendDefinition = $dddDefinition['extend']; if (!array_key_exists('extend', $properties)) { $properties['extend'] = $dddExtendDefinition; //No multi-inheritance } } $dddReferenceFields = []; if (array_key_exists('fields', $dddDefinition)) { foreach ($dddDefinition['fields'] as $key => $value) { $dddReferenceFields[$key] = $value; } } //TODO: gestire gli [] dentro la definizione del modello se serve... //TODO: aggiungere le validazioni // validationRule: // events: // create: // fields: [ id, sessione, tipologiaCampo] // delete: // fields: [ id ] // addDocument: // fields: [ id, documentoCorrelato ] if (array_key_exists('events', $properties)) { //genero altre classi per ogni evento! $eventsProperties = $this->rym->getDomainDefinitionAttributes('events'); $eventsNamespace = $eventsProperties['package']; $eventsImplement = ''; if (array_key_exists('implement', $eventsProperties)) { $eventsImplement = $eventsProperties['implement']; } $eventsExtend = ''; if (array_key_exists('extend', $eventsProperties)) { $eventsExtend = $eventsProperties['extend']; } if (!array_key_exists($eventsImplement, $this->modelClass)) { $this->error('Missing implement class ' . $eventsImplement, ['class' => $className]); $this->errors[] = 'Missing implement ' . $eventsImplement . ' for ' . $className; continue; } $namespaceImplementClass = $this->modelClass[$eventsImplement]; $eventsImplementFull = $namespaceImplementClass . '\\' . $eventsImplement; $eventsField = []; if (array_key_exists('fields', $eventsProperties)) { foreach ($eventsProperties['fields'] as $key => $value) { $eventsField[$key] = $value; } } //field's inheritance if (array_key_exists($eventsImplementFull, $this->fieldsClass)) { $fieldsImplementClass = $this->fieldsClass[$eventsImplementFull]; foreach ($fieldsImplementClass as $key => $value) { $eventsField[$key] = $value; } } $eventsToCreate = []; if (array_key_exists('events', $properties)) { $eventsToCreate = $properties['events']; } if (array_key_exists('events', $dddDefinition)) { $eventsToCreate = array_merge($dddDefinition['events'], $eventsToCreate); } foreach ($eventsToCreate as $event) { $eventClassName = $className . str_replace('_', '', ucwords($event, '_')) . 'Event'; $eventClassComments = 'Event ' . $event . ' for Aggregate Root ' . $className; $propertiesEventClass = []; if (!empty($eventsExtend)) { $propertiesEventClass['extend'] = $eventsExtend; } if (!empty($eventsImplement)) { $propertiesEventClass['implements'] = $eventsImplementFull; } $propertiesEventClass['fields'] = $eventsField; $this->info('Create Event', ['event' => $event, 'class' => $className, 'extend' => $eventsExtend, 'implement' => $eventsImplementFull, 'fields' => $eventsField]); $g = new ClassGenerator($eventsNamespace, $eventClassName, $eventClassComments); $g->setLogger($this->logger); $config = new ClassConfig(); $config->isInterface = false; $config->haveConstructor = true; $config->isFinalClass = true; //don't wnat cycle dependency $config->haveGetter = true; $config->haveSetter = false; $g->generateClassType($propertiesEventClass, $this->modelClass, $this->modelComments, $config); $g->createFileOnDir($directoryOutput); $generated = true; } if ($generated) { $this->fieldsClass[$namespace . '\\' . $className] = $eventsField; //ONLY IF VALID!!! } } if (array_key_exists('enum', $properties)) { $enumClassList = $properties['enum']; foreach ($enumClassList as $enumClassName) { $enumNamespace = $namespace . '\\' . $className; $propertiesEnumClass = ['extend' => $namespace . '\\' . $className]; $actionName = 'instance'; $propertiesEnumClass['methods'] = []; $propertiesEnumClass['methods'][$actionName] = []; $propertiesEnumClass['methods'][$actionName]['params'] = []; $propertiesEnumClass['methods'][$actionName]['static'] = true; $propertiesEnumClass['methods'][$actionName]['@return'] = $enumNamespace . '\\' . $enumClassName; $body = 'self::$instance = new ' . $enumClassName . '();'; $body .= 'return self::$instance;'; $propertiesEnumClass['methods'][$actionName]['body'] = $body; //TODO: pensare se qui va bene cosi... potrebbe il ClassGenerator sapere come fare questo costruttore? $actionName = '__construct'; $propertiesEnumClass['methods'][$actionName] = []; $propertiesEnumClass['methods'][$actionName]['visibility'] = 'private'; $propertiesEnumClass['methods'][$actionName]['params'] = []; $propertiesEnumClass['methods'][$actionName]['static'] = false; $propertiesEnumClass['methods'][$actionName]['description'] = 'costruttore'; $body = '$this->name = \'' . $enumClassName . '\';'; $propertiesEnumClass['methods'][$actionName]['body'] = $body; $enumClassComments = 'Child of ' . $className . ' ' . $enumClassName; $g = new ClassGenerator($enumNamespace, $enumClassName, $enumClassComments); $g->setLogger($this->logger); $configEnum = new ClassConfig(); $configEnum->isInterface = false; $configEnum->haveConstructor = true; $configEnum->isFinalClass = true; //don't wnat cycle dependency $configEnum->haveGetter = true; $configEnum->haveSetter = false; $g->generateClassType($propertiesEnumClass, $this->modelClass, $this->modelComments, $configEnum); $g->createFileOnDir($directoryOutput); $generated = true; } $properties['fields']['name'] = ['primitive' => 'string', 'description' => 'nome esplicativo della enum', 'getter' => true]; $config = new ClassConfig(); $config->isInterface = false; $config->haveConstructor = false; $config->isFinalClass = false; $config->isEnum = true; $config->haveGetter = $createGetter; $config->haveSetter = $createSetter; } else { $config = new ClassConfig(); $config->isInterface = false; $config->haveConstructor = true; $config->isFinalClass = true; //don't wnat cycle dependency $config->haveGetter = $createGetter; $config->haveSetter = $createSetter; } //NORMAL GENERATION $g = new ClassGenerator($namespace, $className, $classComments); $g->setLogger($this->logger); $g->generateClassType($properties, $this->modelClass, $this->modelComments, $config); $g->createFileOnDir($directoryOutput); $generated = true; } } if ($generated) { $this->modelClass[$className] = $namespace; $this->modelComments[$className] = $classComments; } } //end class generation }