/** * * INTERNAL: Performance sensitive method * * @throws \Doctrine\OXM\Mapping\MappingException * @param \XMLReader $cursor * @return object */ private function doUnmarshal(XMLReader $cursor) { $allMappedXmlNodes = $this->classMetadataFactory->getAllXmlNodes(); $knownMappedNodes = array_keys($allMappedXmlNodes); if ($cursor->nodeType !== XMLReader::ELEMENT) { throw MarshallerException::invalidMarshallerState($cursor); } $elementName = $cursor->localName; if (!in_array($elementName, $knownMappedNodes)) { throw MappingException::invalidMapping($elementName); } $classMetadata = $this->classMetadataFactory->getMetadataFor($allMappedXmlNodes[$elementName]); $mappedObject = $classMetadata->newInstance(); // Pre Unmarshal hook if ($classMetadata->hasLifecycleCallbacks(Events::preUnmarshal)) { $classMetadata->invokeLifecycleCallbacks(Events::preUnmarshal, $mappedObject); } if ($cursor->hasAttributes) { while ($cursor->moveToNextAttribute()) { if ($classMetadata->hasXmlField($cursor->name)) { $fieldName = $classMetadata->getFieldName($cursor->name); $fieldMapping = $classMetadata->getFieldMapping($fieldName); $type = Type::getType($fieldMapping['type']); if ($classMetadata->isRequired($fieldName) && $cursor->value === null) { throw MappingException::fieldRequired($classMetadata->name, $fieldName); } if ($classMetadata->isCollection($fieldName)) { $convertedValues = array(); foreach (explode(" ", $cursor->value) as $value) { $convertedValues[] = $type->convertToPHPValue($value); } $classMetadata->setFieldValue($mappedObject, $fieldName, $convertedValues); } else { $classMetadata->setFieldValue($mappedObject, $fieldName, $type->convertToPHPValue($cursor->value)); } } } $cursor->moveToElement(); } if (!$cursor->isEmptyElement) { $collectionElements = array(); while (true) { $cursor->read(); if ($cursor->nodeType === XMLReader::END_ELEMENT && $cursor->name === $elementName) { // we're at the original element closing node, bug out break; } if ($cursor->nodeType !== XMLReader::ELEMENT) { // skip insignificant elements continue; } if ($classMetadata->hasXmlField($cursor->localName)) { $fieldName = $classMetadata->getFieldName($cursor->localName); // Check for mapped entity as child, add recursively $fieldMapping = $classMetadata->getFieldMapping($fieldName); if ($this->classMetadataFactory->hasMetadataFor($fieldMapping['type'])) { if ($classMetadata->isCollection($fieldName)) { $collectionElements[$fieldName][] = $this->doUnmarshal($cursor); } else { $classMetadata->setFieldValue($mappedObject, $fieldName, $this->doUnmarshal($cursor)); } } else { // assume text element (dangerous?) $cursor->read(); if ($cursor->nodeType !== XMLReader::TEXT) { throw MarshallerException::invalidMarshallerState($cursor); } $type = Type::getType($fieldMapping['type']); if ($classMetadata->isCollection($fieldName)) { $collectionElements[$fieldName][] = $type->convertToPHPValue($cursor->value); } else { $classMetadata->setFieldValue($mappedObject, $fieldName, $type->convertToPHPValue($cursor->value)); } $cursor->read(); } } elseif (in_array($cursor->name, $knownMappedNodes)) { // look for inherited child directly $childClassMetadata = $this->classMetadataFactory->getMetadataFor($allMappedXmlNodes[$cursor->name]); // todo: ensure this potential child inherits from parent correctly $fieldName = null; foreach ($classMetadata->getFieldMappings() as $fieldMapping) { if ($fieldMapping['type'] == $allMappedXmlNodes[$cursor->name]) { $fieldName = $fieldMapping['fieldName']; } else { // Walk parent tree foreach ($childClassMetadata->getParentClasses() as $parentClass) { if ($fieldMapping['type'] == $parentClass) { $fieldName = $fieldMapping['fieldName']; } } } } if ($fieldName !== null) { if ($classMetadata->isCollection($fieldName)) { $collectionElements[$fieldName][] = $this->doUnmarshal($cursor); } else { $classMetadata->setFieldValue($mappedObject, $fieldName, $this->doUnmarshal($cursor)); } } } } if (!empty($collectionElements)) { foreach ($collectionElements as $fieldName => $elements) { $classMetadata->setFieldValue($mappedObject, $fieldName, $elements); } } } // PostUnmarshall hook if ($classMetadata->hasLifecycleCallbacks(Events::postUnmarshal)) { $classMetadata->invokeLifecycleCallbacks(Events::postUnmarshal, $mappedObject); } return $mappedObject; }