/** * @return MetaConfiguration **/ private function processClasses(SimpleXMLElement $xml, $metafile, $generate) { foreach ($xml->classes[0] as $xmlClass) { $name = (string) $xmlClass['name']; Assert::isFalse(isset($this->classes[$name]), 'class name collision found for ' . $name); $class = new MetaClass($name); if (isset($xmlClass['source'])) { $class->setSourceLink((string) $xmlClass['source']); } if (isset($xmlClass['table'])) { $class->setTableName((string) $xmlClass['table']); } if (isset($xmlClass['type'])) { $type = (string) $xmlClass['type']; if ($type == 'spooked') { $this->getOutput()->warning($class->getName(), true)->warningLine(': uses obsoleted "spooked" type.')->newLine(); } $class->setType(new MetaClassType((string) $xmlClass['type'])); } // lazy existence checking if (isset($xmlClass['extends'])) { $this->liaisons[$class->getName()] = (string) $xmlClass['extends']; } // populate implemented interfaces foreach ($xmlClass->implement as $xmlImplement) { $class->addInterface((string) $xmlImplement['interface']); } if (isset($xmlClass->properties[0]->identifier)) { $id = $xmlClass->properties[0]->identifier; if (!isset($id['name'])) { $name = 'id'; } else { $name = (string) $id['name']; } if (!isset($id['type'])) { $type = 'BigInteger'; } else { $type = (string) $id['type']; } $property = $this->makeProperty($name, $type, $class, (string) $id['size']); if (isset($id['column'])) { $property->setColumnName((string) $id['column']); } elseif ($property->getType() instanceof ObjectType && !$property->getType()->isGeneric()) { $property->setColumnName($property->getConvertedName() . '_id'); } else { $property->setColumnName($property->getConvertedName()); } $property->setIdentifier(true)->required(); $class->addProperty($property); unset($xmlClass->properties[0]->identifier); } $class->setPattern($this->guessPattern((string) $xmlClass->pattern['name'])); if ((string) $xmlClass->pattern['fetch'] == 'cascade') { $class->setFetchStrategy(FetchStrategy::cascade()); } if ($class->getPattern() instanceof InternalClassPattern) { Assert::isTrue($metafile === ONPHP_META_PATH . 'internal.xml', 'internal classes can be defined only in onPHP, sorry'); } elseif ($class->getPattern() instanceof SpookedClassPattern || $class->getPattern() instanceof SpookedEnumerationPattern) { $class->setType(new MetaClassType(MetaClassType::CLASS_SPOOKED)); } // populate properties foreach ($xmlClass->properties[0] as $xmlProperty) { $property = $this->makeProperty((string) $xmlProperty['name'], (string) $xmlProperty['type'], $class, (string) $xmlProperty['size']); if (isset($xmlProperty['column'])) { $property->setColumnName((string) $xmlProperty['column']); } elseif ($property->getType() instanceof ObjectType && !$property->getType()->isGeneric()) { if (isset($this->classes[$property->getType()->getClassName()]) && $property->getType()->getClass()->getPattern() instanceof InternalClassPattern) { throw new UnimplementedFeatureException('you can not use internal classes directly atm'); } $property->setColumnName($property->getConvertedName() . '_id'); } else { $property->setColumnName($property->getConvertedName()); } if ((string) $xmlProperty['required'] == 'true') { $property->required(); } if (isset($xmlProperty['identifier'])) { throw new WrongArgumentException('obsoleted identifier description found in ' . "{$class->getName()} class;\n" . 'you must use <identifier /> instead.'); } if (!$property->getType()->isGeneric()) { if (!isset($xmlProperty['relation'])) { throw new MissingElementException('relation should be set for non-generic ' . "property '{$property->getName()}' type '" . get_class($property->getType()) . "'" . " of '{$class->getName()}' class"); } else { $property->setRelation(MetaRelation::makeFromName((string) $xmlProperty['relation'])); if ($fetch = (string) $xmlProperty['fetch']) { Assert::isTrue($property->getRelationId() == MetaRelation::ONE_TO_ONE, 'fetch mode can be specified only for OneToOne relations'); if ($fetch == 'lazy') { $property->setFetchStrategy(FetchStrategy::lazy()); } elseif ($fetch == 'cascade') { $property->setFetchStrategy(FetchStrategy::cascade()); } else { throw new WrongArgumentException('strange fetch mode found - ' . $fetch); } } if ($property->getRelationId() == MetaRelation::ONE_TO_ONE && $property->getFetchStrategyId() != FetchStrategy::LAZY && $property->getType()->getClassName() != $class->getName()) { $this->references[$property->getType()->getClassName()][] = $class->getName(); } } } if (isset($xmlProperty['default'])) { // will be correctly autocasted further down the code $property->getType()->setDefault((string) $xmlProperty['default']); } $class->addProperty($property); } $class->setBuild($generate); $this->classes[$class->getName()] = $class; } return $this; }