ClassMetadata.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. <?php
  2. /*
  3. * Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace JMS\SerializerBundle\Metadata;
  18. use JMS\SerializerBundle\Exception\InvalidArgumentException;
  19. use Metadata\MergeableInterface;
  20. use Metadata\MethodMetadata;
  21. use Metadata\MergeableClassMetadata;
  22. /**
  23. * Class Metadata used to customize the serialization process.
  24. *
  25. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  26. */
  27. class ClassMetadata extends MergeableClassMetadata
  28. {
  29. const ACCESSOR_ORDER_UNDEFINED = 'undefined';
  30. const ACCESSOR_ORDER_ALPHABETICAL = 'alphabetical';
  31. const ACCESSOR_ORDER_CUSTOM = 'custom';
  32. public $preSerializeMethods = array();
  33. public $postSerializeMethods = array();
  34. public $postDeserializeMethods = array();
  35. public $xmlRootName;
  36. public $accessorOrder;
  37. public $customOrder;
  38. /**
  39. * Sets the order of properties in the class.
  40. *
  41. * @param string $order
  42. * @param array $customOrder
  43. */
  44. public function setAccessorOrder($order, array $customOrder = array())
  45. {
  46. if (!in_array($order, array(self::ACCESSOR_ORDER_UNDEFINED, self::ACCESSOR_ORDER_ALPHABETICAL, self::ACCESSOR_ORDER_CUSTOM), true)) {
  47. throw new \InvalidArgumentException(sprintf('The accessor order "%s" is invalid.', $order));
  48. }
  49. foreach ($customOrder as $name) {
  50. if (!is_string($name)) {
  51. throw new \InvalidArgumentException(sprintf('$customOrder is expected to be a list of strings, but got element of value %s.', json_encode($name)));
  52. }
  53. }
  54. $this->accessorOrder = $order;
  55. $this->customOrder = array_flip($customOrder);
  56. $this->sortProperties();
  57. }
  58. public function addPropertyMetadata(PropertyMetadata $metadata)
  59. {
  60. parent::addPropertyMetadata($metadata);
  61. $this->sortProperties();
  62. }
  63. public function addPreSerializeMethod(MethodMetadata $method)
  64. {
  65. $this->preSerializeMethods[] = $method;
  66. }
  67. public function addPostSerializeMethod(MethodMetadata $method)
  68. {
  69. $this->postSerializeMethods[] = $method;
  70. }
  71. public function addPostDeserializeMethod(MethodMetadata $method)
  72. {
  73. $this->postDeserializeMethods[] = $method;
  74. }
  75. public function merge(MergeableInterface $object)
  76. {
  77. if (!$object instanceof ClassMetadata) {
  78. throw new InvalidArgumentException('$object must be an instance of ClassMetadata.');
  79. }
  80. parent::merge($object);
  81. $this->preSerializeMethods = array_merge($this->preSerializeMethods, $object->preSerializeMethods);
  82. $this->postSerializeMethods = array_merge($this->postSerializeMethods, $object->postSerializeMethods);
  83. $this->postDeserializeMethods = array_merge($this->postDeserializeMethods, $object->postDeserializeMethods);
  84. $this->xmlRootName = $object->xmlRootName;
  85. if ($object->accessorOrder) {
  86. $this->accessorOrder = $object->accessorOrder;
  87. $this->customOrder = $object->customOrder;
  88. }
  89. $this->sortProperties();
  90. }
  91. public function serialize()
  92. {
  93. $this->sortProperties();
  94. return serialize(array(
  95. $this->preSerializeMethods,
  96. $this->postSerializeMethods,
  97. $this->postDeserializeMethods,
  98. $this->xmlRootName,
  99. $this->accessorOrder,
  100. $this->customOrder,
  101. parent::serialize(),
  102. ));
  103. }
  104. public function unserialize($str)
  105. {
  106. list(
  107. $this->preSerializeMethods,
  108. $this->postSerializeMethods,
  109. $this->postDeserializeMethods,
  110. $this->xmlRootName,
  111. $this->accessorOrder,
  112. $this->customOrder,
  113. $parentStr
  114. ) = unserialize($str);
  115. parent::unserialize($parentStr);
  116. }
  117. private function sortProperties()
  118. {
  119. switch ($this->accessorOrder) {
  120. case self::ACCESSOR_ORDER_ALPHABETICAL:
  121. ksort($this->propertyMetadata);
  122. break;
  123. case self::ACCESSOR_ORDER_CUSTOM:
  124. $order = $this->customOrder;
  125. uksort($this->propertyMetadata, function($a, $b) use ($order) {
  126. $existsA = isset($order[$a]);
  127. $existsB = isset($order[$b]);
  128. if (!$existsA && !$existsB) {
  129. return 0;
  130. }
  131. if (!$existsA) {
  132. return 1;
  133. }
  134. if (!$existsB) {
  135. return -1;
  136. }
  137. return $order[$a] < $order[$b] ? -1 : 1;
  138. });
  139. break;
  140. }
  141. }
  142. }