/** * Generate UML diagram code. * * @return bool */ public function generate() { $this->line('@startuml'); foreach ($this->builder->getDocuments() as $document) { $this->renderDocument($document); } $this->line('@enduml'); return join("\n", $this->lines); }
/** * Export UML classes diagram to specified file, all found Documents with their fields, methods * and compositions will be used to generate such UML. * * @param string $filename * @return bool */ public function export($filename) { $this->line('@startuml'); foreach ($this->builder->getDocuments() as $document) { $this->renderDocument($document); } $this->line('@enduml'); return $this->files->write($filename, join("\n", $this->lines)); }
/** * {@inheritdoc} */ protected function renderEntity(ReflectionEntity $entity) { if (!$entity instanceof DocumentSchema) { throw new DocumenterException("Unsupported entity type."); } $element = parent::renderEntity($entity); //Invalid methods if (!empty($entity->getFields()['_id'])) { $element->property('_id', '\\MongoId')->setAccess(AbstractElement::ACCESS_PUBLIC); } //Element Document must have defined create method $element->method('create', ['@param array|\\Traversable $fields', '@return ' . $entity->getShortName()], ['fields'])->setStatic(true)->parameter('fields')->setOptional(true, []); //Document has collection, let's clarify static methods if (!empty($entity->getCollection())) { $parent = $entity->getName(); $return = $entity->getShortName(); if ($entity->getParent(true) != $entity) { //Document parent (related to same collection) $parent = $entity->getParent(true)->getName(); $return = $entity->getShortName() . '|\\' . $parent; } $find = $this->helper('collection', $parent) . '|' . $this->helper('cursor', $parent) . '|\\' . $parent . '[]'; //Static collection methods $element->method('find', ['@param array $query', '@return ' . $find], ['query'])->setStatic(true)->parameter('query')->setOptional(true, [])->setType('array'); $findOne = $element->method('findOne', ['@param array $query', '@param array $sortBy', '@return ' . $return . '|null'], ['query', 'sortBy'])->setStatic(true); $findOne->parameter('query')->setOptional(true, [])->setType('array'); $findOne->parameter('sortBy')->setOptional(true, [])->setType('array'); $element->method('findByPK', ['@param mixed $mongoID', '@return ' . $return . '|null'], ['mongoID'])->setStatic(true); } //Composition (we only need to handle MANY compositions) foreach ($entity->getCompositions() as $name => $composition) { if ($composition['type'] == ODM::CMP_ONE) { continue; } //We are going to create helper compositor class $class = $composition['class']; $element->property($name, '@var ' . $this->helper('compositor', $class) . '|\\' . $class . '[]'); $element->method('get' . ucfirst($name))->setComment('@return ' . $this->helper('compositor', $class) . '|\\' . $class . '[]'); } //Aggregations foreach ($entity->getAggregations() as $name => $aggregation) { $aggregated = $this->builder->document($aggregation['class']); $parent = $aggregated->getParent(true)->getName(); if ($aggregation['type'] == Document::ONE) { //Simple ONE aggregation $element->method($name, ['@return \\' . $parent]); } else { $find = $this->helper('collection', $parent) . '|' . $this->helper('cursor', $parent) . '|\\' . $parent . '[]'; $element->method($name, ['@param array $query', '@return ' . $find], ['query'])->parameter('query')->setOptional(true, [])->setType('array'); } } return $element; }
/** * Resolve mutator aliases and normalize accessor definitions. * * @param array $mutators * @return array */ private function normalizeMutators(array $mutators) { foreach ($mutators as $mutator => &$filters) { foreach ($filters as $field => $filter) { $filters[$field] = $this->builder->mutatorAlias($filter); if ($mutator == self::MUTATOR_ACCESSOR && is_string($filters[$field])) { $type = null; if (!empty($this->getFields()[$field])) { $type = $this->getFields()[$field]; } $filters[$field] = [$filters[$field], is_array($type) ? $type[0] : $type]; } } unset($filters); } return $mutators; }