如何使用我的类/对象使用Symfony Serializer添加/更新xml属性?

时间:2018-01-26 10:43:42

标签: symfony xmlserializer serializer

我有以下代码示例,它定义了一个可以保存姓名和电话号码列表的Contact类。我想要做的是设置" primary"的属性。在所有数字上,其值为' 1'其中一个是任意的,' 0' 0其余的。

我真的很喜欢使用类方法来做这件事,但是找不到使用setter做到这一点的方法 - 是否可能以某种方式?

这是我的代码。在其中我:

  1. 创建我的对象并设置其属性
  2. print_r Contact对象以查看其存储方式
  3. 反序列化我希望能够生成的xml 相同的联系对象
  4. print_r Contact对象以查看其存储方式
  5. 使用setter
  6. 添加另一个号码
  7. print_r Contact对象以查看其存储方式
  8. 序列化为xml并查看如何处理对象和数组的混合
  9. 打印xml
  10. <?php
    // Symfony Serializer experiment  
    
    require $_SERVER['DOCUMENT_ROOT'].'/libraries/symfony/vendor/autoload.php';
    
    use Symfony\Component\Serializer\Serializer;
    use Symfony\Component\Serializer\Encoder\XmlEncoder;
    use Symfony\Component\Serializer\Encoder\JsonEncoder;
    use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
    use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
    
    Class Number { 
        private $Number;
        private $Type;
        // Getters    
        public function getNumber()
        {
            return $this->Number;
        }
        public function getType()
        {
            return $this->Type;
        }     
        // Setters    
        public function setNumber($number)
        {
            $this->Number = $number;
    
            return $this;
        } 
        public function setType($type)
        {
            $this->Type = $type;
    
            return $this;
        }                 
    } 
    
    class Contact
    {
        private $Name;
        private $Numbers = array();
    
        function __construct() {
            ${@Primary} = 0;    
        }
    
        // Getters
        public function getName()
        {
            return $this->Name;
        }
        public function getNumbers()
        {
            return $this->Numbers;
        }  
        // Setters
        public function setName($name)
        {
            $this->Name = $name;
    
            return $this;        
        }
        public function setNumbers($numbers)
        {
            $this->Numbers = $numbers;
    
            return $this;        
        }
        public function addNumber($number) {
            $this->Numbers['Number'][] = $number;
        }    
    }
    
    // Serializer setup
    
    $xmlEncoder = new XmlEncoder();
    $xmlEncoder->setRootNodeName('Contact');                
    $encoders = array($xmlEncoder, new JsonEncoder());
    $normalizers = array(new ObjectNormalizer());
    $serializer = new Serializer($normalizers, $encoders);
    
    // Create my object
    
    $contact = new Contact();
    $contact->setName('baa');
    $number = new Number();
    $number->setNumber('07878386123')->setType('Mobile');
    $contact->addNumber($number);
    
    // take a look at how it's stored
    
    echo "<pre lang=xml>";
    print_r($contact);
    echo "</pre><br><br>";
    
    // deserialize my desired xml into the same object
    
    $data = <<<EOF
    <Contact>
        <Name>foo</Name>
        <Numbers>
            <Number primary='1'>
                <Number>07878386459</Number>
                <Type>Mobile</Type>
            </Number>    
            <Number primary='0'>
                <Number>02380860835</Number>
                <Type>Landline</Type>
            </Number>            
        </Numbers>        
    </Contact>
    EOF;
    
    $contact = $serializer->deserialize($data, Contact::class, 'xml', array('object_to_populate' => $contact));
    
    // take a look at how it's stored
    
    echo "<pre lang=xml>";
    print_r($contact);
    echo "</pre><br><br>";
    
    // Add another number
    
    $number = new Number();
    $number->setNumber('02387345123')->setType('Landline');
    $contact->addNumber($number);
    
    // take a look at how it's stored
    
    echo "<pre lang=xml>";
    print_r($contact);
    echo "</pre><br><br>";
    
    // serialize  to xml and see how the mixture of objects and arrays are treated
    
    $xmlContent = $serializer->serialize($contact, 'xml');
    
    $dom = new domDocument( '1.0', 'utf-8' );
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;
    $result = $dom->loadXML($xmlContent);
    $xmlContentFormatted=htmlentities($dom->saveXML());
    ?>
    <pre lang=xml><?= $xmlContentFormatted ?></pre>
    

    我在输出中看到的是:

    2)

    Contact Object
    (
        [Name:Contact:private] => baa
        [Numbers:Contact:private] => Array
            (
                [Number] => Array
                    (
                        [0] => Number Object
                            (
                                [Number:Number:private] => 07878386123
                                [Type:Number:private] => Mobile
                            )   
                    )   
            )   
    )
    

    4)

    Contact Object
    (
        [Name:Contact:private] => foo
        [Numbers:Contact:private] => Array
            (
                [Number] => Array
                    (
                        [0] => Array
                            (
                                [@primary] => 1
                                [Number] => 07878386459
                                [Type] => Mobile
                            )    
                        [1] => Array
                            (
                                [@primary] => 0
                                [Number] => 02380860835
                                [Type] => Landline
                            )   
                    )   
    
    )
    

    6)对象和数组的混合。我可以编码我的Number类,以便它使用数组而不是属性,并有另一种方法来设置属性? (例如

    $number->setNumber('07878386123')->setType('Mobile')->addAttr(array('primary' => '1'));
    
    Contact Object
    (
        [Name:Contact:private] => foo
        [Numbers:Contact:private] => Array
            (
                [Number] => Array
                    (
                        [0] => Array
                            (
                                [@primary] => 1
                                [Number] => 07878386459
                                [Type] => Mobile
                            )    
                        [1] => Array
                            (
                                [@primary] => 0
                                [Number] => 02380860835
                                [Type] => Landline
                            )
    
                        [2] => Number Object
                            (
                                [Number:Number:private] => 02387345123
                                [Type:Number:private] => Landline
                            )    
                    )    
            )    
    )    
    

    8)

    <?xml version="1.0"?>
    <Contact>
      <Name>foo</Name>
      <Numbers>
        <Number primary="1">
          <Number>07878386459</Number>
          <Type>Mobile</Type>
        </Number>
        <Number primary="0">
          <Number>02380860835</Number>
          <Type>Landline</Type>
        </Number>
        <Number>
          <Number>02387345123</Number>
          <Type>Landline</Type>
        </Number>
      </Numbers>
    </Contact>
    

    当从具有使用属性的标签的XML反序列化时,php对象使用数组,因此如果你想从可以赋予属性的php表示开始,你需要使用数组。

1 个答案:

答案 0 :(得分:1)

相当不成熟的黑客,但设法找到一种方法使其工作。修改后的例子现在可以满足我的需求:

<?php
// Symfony Serializer experiment  

require $_SERVER['DOCUMENT_ROOT'].'/libraries/symfony/vendor/autoload.php';

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;

// build datastructure as array
Class Number { 
    private $data;

    public function __construct(array $attributes) {
        $data = ['Number'];
        foreach ($attributes as $name => $value) {
            $this->data['Number']['@'.$name] = $value;
        }
    }

    // Getters    
    public function getNumber()
    {
        return $this->data['Number']['Number'];
    }
    public function getType()
    {
        return $this->data['Number']['Type'];
    }

    public function get() 
    {
        return $this->data['Number'];    
    }         
    // Setters    
    public function setNumber($number)
    {
        $this->data['Number']['Number'] = $number;

        return $this;
    } 
    public function setType($type)
    {
        $this->data['Number']['Type'] = $type;

        return $this;
    }

}

class Contact
{
    private $data;

    // Getters
    public function getName()
    {
        return $this->data['Contact']['Name'];
    }
    public function getNumbers()
    {
        return $this->data['Contact']['Numbers'];
    }
    public function get() 
    {
        return $this->data['Contact']; // this is the top level so return the Contact element, not data.    
    }      
    // Setters
    public function setName($name)
    {
        $this->data['Contact']['Name'] = $name;        

        return $this;        
    }
    public function setNumbers($numbers)
    {
        $this->data['Contact']['Numbers'] = $numbers;        

        return $this;        
    }
    public function addNumber($number) {
        $this->data['Contact']['Numbers']['Number'][] = $number;
    }    
}

// Serializer setup

$xmlEncoder = new XmlEncoder();
$xmlEncoder->setRootNodeName('Contact');                
$encoders = array($xmlEncoder, new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$encoder = new \Symfony\Component\Serializer\Encoder\XmlEncoder();

// Create my object

$contact = (new Contact)->setName('Foo Bar');
$number = (new Number(array('primary'=>'1')))->setNumber('07878386123')->setType('Mobile');
$number_data = $number->get();
$contact->addNumber($number_data);
$number = (new Number(array('primary'=>'0')))->setNumber('02380876345')->setType('Landline');
$number_data = $number->get();
$contact->addNumber($number_data);

echo "<pre lang=xml>";
print_r($contact);
echo "</pre><br><br>";

$xmlContent = $serializer->serialize($contact->get(), 'xml');

$dom = new domDocument( '1.0', 'utf-8' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$result = $dom->loadXML($xmlContent);
$xmlContentFormatted=htmlentities($dom->saveXML());
?>
<pre lang=xml><?= $xmlContentFormatted ?></pre> 

输出:

Contact Object
(
    [data:Contact:private] => Array
        (
            [Contact] => Array
                (
                    [Name] => Foo Bar
                    [Numbers] => Array
                        (
                            [Number] => Array
                                (
                                    [0] => Array
                                        (
                                            [@primary] => 1
                                            [Number] => 07878386123
                                            [Type] => Mobile
                                        )

                                    [1] => Array
                                        (
                                            [@primary] => 0
                                            [Number] => 02380876345
                                            [Type] => Landline
                                        )
                                )
                        )
                )
        )
)


<?xml version="1.0"?>
<Contact>
  <Name>Foo Bar</Name>
  <Numbers>
    <Number primary="1">
      <Number>07878386123</Number>
      <Type>Mobile</Type>
    </Number>
    <Number primary="0">
      <Number>02380876345</Number>
      <Type>Landline</Type>
    </Number>
  </Numbers>
</Contact>