/** * return the schema for a given route * * @param string $modelName name of mode to generate schema for * @param DocumentModel $model model to generate schema for * @param boolean $online if we are online and have access to mongodb during this build * * @return Schema */ public function getModelSchema($modelName, DocumentModel $model, $online = true) { // build up schema data $schema = new Schema(); if (!empty($model->getTitle())) { $schema->setTitle($model->getTitle()); } else { $schema->setTitle(ucfirst($modelName)); } $schema->setDescription($model->getDescription()); $schema->setType('object'); // grab schema info from model $repo = $model->getRepository(); $meta = $repo->getClassMetadata(); // look for translatables in document class $documentReflection = new \ReflectionClass($repo->getClassName()); if ($documentReflection->implementsInterface('Graviton\\I18nBundle\\Document\\TranslatableDocumentInterface')) { /** @var TranslatableDocumentInterface $documentInstance */ $documentInstance = $documentReflection->newInstanceWithoutConstructor(); $translatableFields = array_merge($documentInstance->getTranslatableFields(), $documentInstance->getPreTranslatedFields()); } else { $translatableFields = []; } // exposed fields $documentFieldNames = isset($this->documentFieldNames[$repo->getClassName()]) ? $this->documentFieldNames[$repo->getClassName()] : []; if ($online) { $languages = array_map(function (Language $language) { return $language->getId(); }, $this->languageRepository->findAll()); } else { $languages = [$this->defaultLocale]; } // exposed events.. $classShortName = $documentReflection->getShortName(); if (isset($this->eventMap[$classShortName])) { $schema->setEventNames(array_unique($this->eventMap[$classShortName]['events'])); } foreach ($meta->getFieldNames() as $field) { // don't describe hidden fields if (!isset($documentFieldNames[$field])) { continue; } $property = new Schema(); $property->setTitle($model->getTitleOfField($field)); $property->setDescription($model->getDescriptionOfField($field)); $property->setType($meta->getTypeOfField($field)); $property->setReadOnly($model->getReadOnlyOfField($field)); if ($meta->getTypeOfField($field) === 'many') { $propertyModel = $model->manyPropertyModelForTarget($meta->getAssociationTargetClass($field)); if ($model->hasDynamicKey($field)) { $property->setType('object'); if ($online) { // we generate a complete list of possible keys when we have access to mongodb // this makes everything work with most json-schema v3 implementations (ie. schemaform.io) $dynamicKeySpec = $model->getDynamicKeySpec($field); $documentId = $dynamicKeySpec->{'document-id'}; $dynamicRepository = $this->repositoryFactory->get($documentId); $repositoryMethod = $dynamicKeySpec->{'repository-method'}; $records = $dynamicRepository->{$repositoryMethod}(); $dynamicProperties = array_map(function ($record) { return $record->getId(); }, $records); foreach ($dynamicProperties as $propertyName) { $property->addProperty($propertyName, $this->getModelSchema($field, $propertyModel, $online)); } } else { // in the swagger case we can use additionPorerties which where introduced by json-schema v4 $property->setAdditionalProperties($this->getModelSchema($field, $propertyModel, $online)); } } else { $property->setItems($this->getModelSchema($field, $propertyModel, $online)); $property->setType('array'); } } elseif ($meta->getTypeOfField($field) === 'one') { $propertyModel = $model->manyPropertyModelForTarget($meta->getAssociationTargetClass($field)); $property = $this->getModelSchema($field, $propertyModel, $online); } elseif (in_array($field, $translatableFields, true)) { $property = $this->makeTranslatable($property, $languages); } elseif (in_array($field . '[]', $translatableFields, true)) { $property = $this->makeArrayTranslatable($property, $languages); } elseif ($meta->getTypeOfField($field) === 'extref') { $urls = array(); $refCollections = $model->getRefCollectionOfField($field); foreach ($refCollections as $collection) { if (isset($this->extrefServiceMapping[$collection])) { $urls[] = $this->router->generate($this->extrefServiceMapping[$collection] . '.all', [], true); } elseif ($collection === '*') { $urls[] = '*'; } } $property->setRefCollection($urls); } elseif ($meta->getTypeOfField($field) === 'collection') { $itemSchema = new Schema(); $property->setType('array'); $itemSchema->setType($this->getCollectionItemType($meta->name, $field)); $property->setItems($itemSchema); $property->setFormat(null); } elseif ($meta->getTypeOfField($field) === 'datearray') { $itemSchema = new Schema(); $property->setType('array'); $itemSchema->setType('string'); $itemSchema->setFormat('date-time'); $property->setItems($itemSchema); $property->setFormat(null); } elseif ($meta->getTypeOfField($field) === 'hasharray') { $itemSchema = new Schema(); $itemSchema->setType('object'); $property->setType('array'); $property->setItems($itemSchema); $property->setFormat(null); } $schema->addProperty($documentFieldNames[$field], $property); } if ($meta->isEmbeddedDocument && !in_array('id', $model->getRequiredFields())) { $schema->removeProperty('id'); } $requiredFields = []; foreach ($model->getRequiredFields() as $field) { // don't describe hidden fields if (!isset($documentFieldNames[$field])) { continue; } $requiredFields[] = $documentFieldNames[$field]; } $schema->setRequired($requiredFields); return $schema; }
/** * return the schema for a given route * * @param string $modelName name of mode to generate schema for * @param object $model model to generate schema for * * @return Schema */ public function getModelSchema($modelName, $model) { // build up schema data $schema = new Schema(); $schema->setTitle(ucfirst($modelName)); $schema->setDescription($model->getDescription()); $schema->setType('object'); // grab schema info from model $repo = $model->getRepository(); $meta = $repo->getClassMetadata(); // look for translatables in document class $entityName = $repo->getClassName(); $translatableFields = array(); if (class_exists($entityName)) { $documentClass = new $entityName(); if ($documentClass instanceof TranslatableDocumentInterface) { $translatableFields = array_merge($documentClass->getTranslatableFields(), $documentClass->getPreTranslatedFields()); } } $languages = array_map(function ($language) { return $language->getId(); }, $this->languageRepository->findAll()); foreach ($meta->getFieldNames() as $field) { // don't describe deletedDate in schema.. if ($field == 'deletedDate') { continue; } $property = new Schema(); $property->setTitle($model->getTitleOfField($field)); $property->setDescription($model->getDescriptionOfField($field)); $property->setType($meta->getTypeOfField($field)); if ($meta->getTypeOfField($field) === 'many') { $propertyModel = $model->manyPropertyModelForTarget($meta->getAssociationTargetClass($field)); $property->setItems(self::getModelSchema($field, $propertyModel)); $property->setType('array'); } if ($meta->getTypeOfField($field) === 'one') { $propertyModel = $model->manyPropertyModelForTarget($meta->getAssociationTargetClass($field)); $property = self::getModelSchema($field, $propertyModel); } if (in_array($field, $translatableFields)) { $property = self::makeTranslatable($property, $languages); } if ($meta->getTypeOfField($field) === 'extref' && substr($field, 0, 1) !== '$') { $field = '$' . $field; } $schema->addProperty($field, $property); } if ($meta->isEmbeddedDocument && !in_array('id', $model->getRequiredFields())) { $schema->removeProperty('id'); } $requiredFields = $model->getRequiredFields(); foreach ($requiredFields as $index => $requiredField) { if ($requiredField === 'ref') { $requiredFields[$index] = '$' . $requiredFields[$index]; } } $schema->setRequired($requiredFields); return $schema; }