什么是将学说实体转换为数组/JSON/XML的正确方法



我正在迁移Zend Framework 3应用程序的ZendDb驱动DBAL到学说。一切都很好,但是现在我对数据导出遇到了问题。

在迁移之前,它的工作原理如下:

有一个或多或少复杂的数据结构。Mapper执行了一些数据库请求,并通过此数据构建了一个嵌套的DataObject。因此,导出的起点是一个对象,充满了所有数据并具有子对象,以及所有数据。因此,我只是将其转换为JSON

public function exportToJson(AbstractDataObject $dataObject)
{
    return json_encode($dataObject, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
public function exportToXml(AbstractDataObject $dataObject)
{
    $dataObjectVars = json_decode(json_encode($dataObject->jsonSerialize()), true);
    $xml = new SimpleXMLElement('<' . self::XML_DEFAULT_ROOT_ELEMENT . ' />');
    $this->arrayToXml($dataObjectVars, $xml);
    $domxml = new DOMDocument('1.0');
    $domxml->preserveWhiteSpace = false;
    $domxml->formatOutput = true;
    $domxml->loadXML($xml->asXML());
    $xmlString = $domxml->saveXML();
    return $xmlString;
}
protected function arrayToXml($array, &$xml)
{
    foreach ($array as $key => $value) {
        if(is_array($value)){
            if(is_int($key)){
                $key = self::XML_DEFAULT_ELEMENT_NAME;
            }
            $label = $xml->addChild($key);
            $this->arrayToXml($value, $label);
        }
        else {
            $xml->addChild($key, $value);
        }
    }
}

所有DataObject S扩展了AbstractDataObject,并提供了一种方法,使其易于导出到JSON

class AbstractDataObject implements JsonSerializable
{
    public function jsonSerialize()
    {
        $reflection = new ReflectionClass($this);
        $properties = $reflection->getProperties();
        $members = [];
        foreach ($properties as $property) {
            $property->setAccessible(true);
            $members[$property->getName()] = $property->getValue($this);
        }
        $keys = array_keys($members);
        $values = array_values($members);
        $keysUnderscored = preg_replace_callback('/([A-Z])/', function($matches) {
            return '_' . strtolower($matches[1]);
        }, $keys);
        $varsUnderscored = array_combine($keysUnderscored, $values);
        return $varsUnderscored;
    }
}

现在,导出的对象是一个实体,通常没有加载其所有数据。这意味着,上述方法不再起作用。

是否存在/什么是将嵌套实体(意味着具有子本性的实体)转换为结构化数据格式(array/JSON/XML)的正确方法?

最后,我正如塞拉德(Cerad)对Symfony Serialializer组件的评论所建议的。

我对编码遇到了一些麻烦:JSON的JSON_ERROR_UTF8和XML的" Warning: DOMDocument::saveXML(): invalid character value"。因此,我必须" UTF8ize"从Serializer接收到的数组数据,并通过使用dom_import_simplexml(...)重新进来exportToXml(...),如下所示。但是现在它正在奏效,我们去这里:

namespace MyNamespaceDataExport;
use MyNamespaceDataObjectAbstractDataObject;
use SymfonyComponentSerializerNameConverterCamelCaseToSnakeCaseNameConverter;
use SymfonyComponentSerializerNormalizerObjectNormalizer;
use SymfonyComponentSerializerSerializer;
use SymfonyComponentSerializerMappingFactoryClassMetadataFactory;
use DoctrineCommonAnnotationsAnnotationReader;
use SymfonyComponentSerializerMappingLoaderAnnotationLoader;
class DataExporter
{
    /** @var string */
    const EXPORT_FORMAT_JSON = 'json';
    /** @var string */
    const EXPORT_FORMAT_XML = 'xml';
    /** @var string */
    const XML_DEFAULT_ROOT_ELEMENT = 'my_root_element_name';
    /** @var string */
    const XML_DEFAULT_ELEMENT_NAME = 'item';
    /** @var Serializer */
    protected $serializer;
    public function __construct()
    {
        $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
        $normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
        $normalizer->setCircularReferenceLimit(1);
        $normalizer->setIgnoredAttributes(['__initializer__', '__cloner__', '__isInitialized__']);
        $normalizer->setCircularReferenceHandler(function ($object) {
            // @todo A cleaner solution need.
            try {
                $return = $object->getId();
            } catch (Error $exception) {
                $return = null;
            }
            $return = null;
            return $return;
        });
        $normalizers = [$normalizer];
        $this->serializer = new Serializer($normalizers);
    }
    public function exportToJson(AbstractDataObject $dataObject)
    {
        $data = $this->serializer->normalize($dataObject, null, ['groups' => ['export']]);
        $data = $this->utf8ize($data);
        return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    }
    public function exportToXml(AbstractDataObject $dataObject)
    {
        $data = $this->serializer->normalize($dataObject, null, ['groups' => ['export']]);
        $data = $this->utf8ize($data);
        $xml = new SimpleXMLElement('<' . self::XML_DEFAULT_ROOT_ELEMENT . ' />');
        $this->arrayToXml($data, $xml);
        $domDocument = dom_import_simplexml($xml)->ownerDocument;
        $domDocument->formatOutput = true;
        $xmlString = $domDocument->saveXML();
        return $xmlString;
    }
    protected function utf8ize($data) {
        if (is_array($data)) {
            foreach ($data as $key => $value) {
                $data[$key] = $this->utf8ize($value);
            }
        } else if (is_string ($data)) {
            return utf8_encode($data);
        }
        return $data;
    }
    /**
     * Converts an $array to XML and
     * saves the result to the $xml argument.
     *
     * @param array $array
     * @param SimpleXMLElement $xml
     * @return void
     */
    protected function arrayToXml($array, &$xml){
        foreach ($array as $key => $value) {
            if(is_array($value)){
                if(is_int($key)){
                    $key = self::XML_DEFAULT_ELEMENT_NAME;
                }
                $label = $xml->addChild($key);
                $this->arrayToXml($value, $label);
            }
            else {
                $xml->addChild($key, $value);
            }
        }
    }
}

相关内容

  • 没有找到相关文章