Prop.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <?php
  2. declare(strict_types=1);
  3. namespace Sabre\DAV\Xml\Element;
  4. use Sabre\DAV\Xml\Property\Complex;
  5. use Sabre\Xml\Reader;
  6. use Sabre\Xml\XmlDeserializable;
  7. /**
  8. * This class is responsible for decoding the {DAV:}prop element as it appears
  9. * in {DAV:}property-update.
  10. *
  11. * This class doesn't return an instance of itself. It just returns a
  12. * key->value array.
  13. *
  14. * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
  15. * @author Evert Pot (http://evertpot.com/)
  16. * @license http://sabre.io/license/ Modified BSD License
  17. */
  18. class Prop implements XmlDeserializable
  19. {
  20. /**
  21. * The deserialize method is called during xml parsing.
  22. *
  23. * This method is called statically, this is because in theory this method
  24. * may be used as a type of constructor, or factory method.
  25. *
  26. * Often you want to return an instance of the current class, but you are
  27. * free to return other data as well.
  28. *
  29. * You are responsible for advancing the reader to the next element. Not
  30. * doing anything will result in a never-ending loop.
  31. *
  32. * If you just want to skip parsing for this element altogether, you can
  33. * just call $reader->next();
  34. *
  35. * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
  36. * the next element.
  37. *
  38. * @return mixed
  39. */
  40. public static function xmlDeserialize(Reader $reader)
  41. {
  42. // If there's no children, we don't do anything.
  43. if ($reader->isEmptyElement) {
  44. $reader->next();
  45. return [];
  46. }
  47. $values = [];
  48. $reader->read();
  49. do {
  50. if (Reader::ELEMENT === $reader->nodeType) {
  51. $clark = $reader->getClark();
  52. $values[$clark] = self::parseCurrentElement($reader)['value'];
  53. } else {
  54. $reader->read();
  55. }
  56. } while (Reader::END_ELEMENT !== $reader->nodeType);
  57. $reader->read();
  58. return $values;
  59. }
  60. /**
  61. * This function behaves similar to Sabre\Xml\Reader::parseCurrentElement,
  62. * but instead of creating deep xml array structures, it will turn any
  63. * top-level element it doesn't recognize into either a string, or an
  64. * XmlFragment class.
  65. *
  66. * This method returns arn array with 2 properties:
  67. * * name - A clark-notation XML element name.
  68. * * value - The parsed value.
  69. *
  70. * @return array
  71. */
  72. private static function parseCurrentElement(Reader $reader)
  73. {
  74. $name = $reader->getClark();
  75. if (array_key_exists($name, $reader->elementMap)) {
  76. $deserializer = $reader->elementMap[$name];
  77. if (is_subclass_of($deserializer, 'Sabre\\Xml\\XmlDeserializable')) {
  78. $value = call_user_func([$deserializer, 'xmlDeserialize'], $reader);
  79. } elseif (is_callable($deserializer)) {
  80. $value = call_user_func($deserializer, $reader);
  81. } else {
  82. $type = gettype($deserializer);
  83. if ('string' === $type) {
  84. $type .= ' ('.$deserializer.')';
  85. } elseif ('object' === $type) {
  86. $type .= ' ('.get_class($deserializer).')';
  87. }
  88. throw new \LogicException('Could not use this type as a deserializer: '.$type);
  89. }
  90. } else {
  91. $value = Complex::xmlDeserialize($reader);
  92. }
  93. return [
  94. 'name' => $name,
  95. 'value' => $value,
  96. ];
  97. }
  98. }