简体   繁体   English

如何使用我的类/对象通过Symfony序列化器添加/更新xml属性?

[英]How do I add/update xml attributes with Symfony Serializer using my class/object?

I have the following code example which defines a Contact class that can hold a name and a list of phone numbers. 我有以下代码示例,该示例定义了一个Contact类,该类可以包含名称和电话号码列表。 What I want to be able to do is set an attribute of "primary" on all the numbers, where the value for it is '1' for one of them arbitrarily, and '0' for the rest. 我想做的是在所有数字上设置一个“ primary”属性,其中任意一个数字的值为“ 1”,其余数字的值为“ 0”。

I'd really like to do this using a class method but couldn't find a way to do this using a setter - is it possible somehow? 我真的很想使用类方法来执行此操作,但找不到使用setter来执行此操作的方法-是否有可能?

Here's my code. 这是我的代码。 In it I: 在其中:

  1. Create my objects and set their properies 创建我的对象并设置其属性
  2. print_r the Contact object to see how it is stored print_r Contact对象以查看其存储方式
  3. Deserialize the xml that I'd like to be able to generate into the same Contact object 将我希望能够生成的xml反序列化为相同的Contact对象
  4. print_r the Contact object to see how it is stored print_r Contact对象以查看其存储方式
  5. Add another number using setter 使用setter添加另一个号码
  6. print_r the Contact object to see how it is stored print_r Contact对象以查看其存储方式
  7. Serialize to xml and see how the mixture of objects and arrays are treated 序列化为xml,看看如何处理对象和数组的混合
  8. print the xml 打印xml

<?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>

What I see in the output is: 我在输出中看到的是:

2) 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) 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) Mixture of objects and arrays. 6)对象和数组的混合。 Could I code my Number class so that it uses an array rather than properties and have another method for setting attribute? 我可以对Number类进行编码,以便它使用数组而不是属性,并使用另一种设置属性的方法吗? (eg (例如

$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) 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>

When deserializing from XML that has tags that use attributes, the php objects use arrays, so it would appear that if you want to start out with a php representation that can be given attributes you need to use arrays. 当从具有使用属性的标签的XML反序列化时,php对象使用数组,因此,如果要开始使用可以被赋予属性的php表示形式,则需要使用数组。

Quite an unsophisticated hack, but managed to find a way to make it work. 相当简单的骇客,但设法找到一种使之起作用的方法。 The modified example now does what I need: 修改后的示例现在可以满足我的需求:

<?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> 

Output: 输出:

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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM