/Metadata/ClassMetadata.php

https://github.com/cystbear/JMSSerializerBundle · PHP · 169 lines · 117 code · 26 blank · 26 comment · 9 complexity · 743c326739c08aaa2d2d0103733eba92 MD5 · raw file

  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. use Metadata\PropertyMetadata as BasePropertyMetadata;
  23. /**
  24. * Class Metadata used to customize the serialization process.
  25. *
  26. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  27. */
  28. class ClassMetadata extends MergeableClassMetadata
  29. {
  30. const ACCESSOR_ORDER_UNDEFINED = 'undefined';
  31. const ACCESSOR_ORDER_ALPHABETICAL = 'alphabetical';
  32. const ACCESSOR_ORDER_CUSTOM = 'custom';
  33. public $preSerializeMethods = array();
  34. public $postSerializeMethods = array();
  35. public $postDeserializeMethods = array();
  36. public $xmlRootName;
  37. public $accessorOrder;
  38. public $customOrder;
  39. /**
  40. * Sets the order of properties in the class.
  41. *
  42. * @param string $order
  43. * @param array $customOrder
  44. */
  45. public function setAccessorOrder($order, array $customOrder = array())
  46. {
  47. if (!in_array($order, array(self::ACCESSOR_ORDER_UNDEFINED, self::ACCESSOR_ORDER_ALPHABETICAL, self::ACCESSOR_ORDER_CUSTOM), true)) {
  48. throw new \InvalidArgumentException(sprintf('The accessor order "%s" is invalid.', $order));
  49. }
  50. foreach ($customOrder as $name) {
  51. if (!is_string($name)) {
  52. throw new \InvalidArgumentException(sprintf('$customOrder is expected to be a list of strings, but got element of value %s.', json_encode($name)));
  53. }
  54. }
  55. $this->accessorOrder = $order;
  56. $this->customOrder = array_flip($customOrder);
  57. $this->sortProperties();
  58. }
  59. public function addPropertyMetadata(BasePropertyMetadata $metadata)
  60. {
  61. parent::addPropertyMetadata($metadata);
  62. $this->sortProperties();
  63. }
  64. public function addPreSerializeMethod(MethodMetadata $method)
  65. {
  66. $this->preSerializeMethods[] = $method;
  67. }
  68. public function addPostSerializeMethod(MethodMetadata $method)
  69. {
  70. $this->postSerializeMethods[] = $method;
  71. }
  72. public function addPostDeserializeMethod(MethodMetadata $method)
  73. {
  74. $this->postDeserializeMethods[] = $method;
  75. }
  76. public function merge(MergeableInterface $object)
  77. {
  78. if (!$object instanceof ClassMetadata) {
  79. throw new InvalidArgumentException('$object must be an instance of ClassMetadata.');
  80. }
  81. parent::merge($object);
  82. $this->preSerializeMethods = array_merge($this->preSerializeMethods, $object->preSerializeMethods);
  83. $this->postSerializeMethods = array_merge($this->postSerializeMethods, $object->postSerializeMethods);
  84. $this->postDeserializeMethods = array_merge($this->postDeserializeMethods, $object->postDeserializeMethods);
  85. $this->xmlRootName = $object->xmlRootName;
  86. if ($object->accessorOrder) {
  87. $this->accessorOrder = $object->accessorOrder;
  88. $this->customOrder = $object->customOrder;
  89. }
  90. $this->sortProperties();
  91. }
  92. public function serialize()
  93. {
  94. $this->sortProperties();
  95. return serialize(array(
  96. $this->preSerializeMethods,
  97. $this->postSerializeMethods,
  98. $this->postDeserializeMethods,
  99. $this->xmlRootName,
  100. $this->accessorOrder,
  101. $this->customOrder,
  102. parent::serialize(),
  103. ));
  104. }
  105. public function unserialize($str)
  106. {
  107. list(
  108. $this->preSerializeMethods,
  109. $this->postSerializeMethods,
  110. $this->postDeserializeMethods,
  111. $this->xmlRootName,
  112. $this->accessorOrder,
  113. $this->customOrder,
  114. $parentStr
  115. ) = unserialize($str);
  116. parent::unserialize($parentStr);
  117. }
  118. private function sortProperties()
  119. {
  120. switch ($this->accessorOrder) {
  121. case self::ACCESSOR_ORDER_ALPHABETICAL:
  122. ksort($this->propertyMetadata);
  123. break;
  124. case self::ACCESSOR_ORDER_CUSTOM:
  125. $order = $this->customOrder;
  126. uksort($this->propertyMetadata, function($a, $b) use ($order) {
  127. $existsA = isset($order[$a]);
  128. $existsB = isset($order[$b]);
  129. if (!$existsA && !$existsB) {
  130. return 0;
  131. }
  132. if (!$existsA) {
  133. return 1;
  134. }
  135. if (!$existsB) {
  136. return -1;
  137. }
  138. return $order[$a] < $order[$b] ? -1 : 1;
  139. });
  140. break;
  141. }
  142. }
  143. }