Json.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <?php
  2. namespace Sabre\VObject\Parser;
  3. use
  4. Sabre\VObject\Component\VCalendar,
  5. Sabre\VObject\Component\VCard,
  6. Sabre\VObject\ParseException,
  7. Sabre\VObject\EofException;
  8. /**
  9. * Json Parser.
  10. *
  11. * This parser parses both the jCal and jCard formats.
  12. *
  13. * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
  14. * @author Evert Pot (http://evertpot.com/)
  15. * @license http://sabre.io/license/ Modified BSD License
  16. */
  17. class Json extends Parser {
  18. /**
  19. * The input data
  20. *
  21. * @var array
  22. */
  23. protected $input;
  24. /**
  25. * Root component
  26. *
  27. * @var Document
  28. */
  29. protected $root;
  30. /**
  31. * This method starts the parsing process.
  32. *
  33. * If the input was not supplied during construction, it's possible to pass
  34. * it here instead.
  35. *
  36. * If either input or options are not supplied, the defaults will be used.
  37. *
  38. * @param resource|string|array|null $input
  39. * @param int|null $options
  40. * @return array
  41. */
  42. public function parse($input = null, $options = null) {
  43. if (!is_null($input)) {
  44. $this->setInput($input);
  45. }
  46. if (is_null($this->input)) {
  47. throw new EofException('End of input stream, or no input supplied');
  48. }
  49. if (!is_null($options)) {
  50. $this->options = $options;
  51. }
  52. switch($this->input[0]) {
  53. case 'vcalendar' :
  54. $this->root = new VCalendar(array(), false);
  55. break;
  56. case 'vcard' :
  57. $this->root = new VCard(array(), false);
  58. break;
  59. default :
  60. throw new ParseException('The root component must either be a vcalendar, or a vcard');
  61. }
  62. foreach($this->input[1] as $prop) {
  63. $this->root->add($this->parseProperty($prop));
  64. }
  65. if (isset($this->input[2])) foreach($this->input[2] as $comp) {
  66. $this->root->add($this->parseComponent($comp));
  67. }
  68. // Resetting the input so we can throw an feof exception the next time.
  69. $this->input = null;
  70. return $this->root;
  71. }
  72. /**
  73. * Parses a component
  74. *
  75. * @param array $jComp
  76. * @return \Sabre\VObject\Component
  77. */
  78. public function parseComponent(array $jComp) {
  79. // We can remove $self from PHP 5.4 onward.
  80. $self = $this;
  81. $properties = array_map(
  82. function($jProp) use ($self) {
  83. return $self->parseProperty($jProp);
  84. },
  85. $jComp[1]
  86. );
  87. if (isset($jComp[2])) {
  88. $components = array_map(
  89. function($jComp) use ($self) {
  90. return $self->parseComponent($jComp);
  91. },
  92. $jComp[2]
  93. );
  94. } else $components = array();
  95. return $this->root->createComponent(
  96. $jComp[0],
  97. array_merge($properties, $components),
  98. $defaults = false
  99. );
  100. }
  101. /**
  102. * Parses properties.
  103. *
  104. * @param array $jProp
  105. * @return \Sabre\VObject\Property
  106. */
  107. public function parseProperty(array $jProp) {
  108. list(
  109. $propertyName,
  110. $parameters,
  111. $valueType
  112. ) = $jProp;
  113. $propertyName = strtoupper($propertyName);
  114. // This is the default class we would be using if we didn't know the
  115. // value type. We're using this value later in this function.
  116. $defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
  117. $parameters = (array)$parameters;
  118. $value = array_slice($jProp, 3);
  119. $valueType = strtoupper($valueType);
  120. if (isset($parameters['group'])) {
  121. $propertyName = $parameters['group'] . '.' . $propertyName;
  122. unset($parameters['group']);
  123. }
  124. $prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
  125. $prop->setJsonValue($value);
  126. // We have to do something awkward here. FlatText as well as Text
  127. // represents TEXT values. We have to normalize these here. In the
  128. // future we can get rid of FlatText once we're allowed to break BC
  129. // again.
  130. if ($defaultPropertyClass === 'Sabre\VObject\Property\FlatText') {
  131. $defaultPropertyClass = 'Sabre\VObject\Property\Text';
  132. }
  133. // If the value type we received (e.g.: TEXT) was not the default value
  134. // type for the given property (e.g.: BDAY), we need to add a VALUE=
  135. // parameter.
  136. if ($defaultPropertyClass !== get_class($prop)) {
  137. $prop["VALUE"] = $valueType;
  138. }
  139. return $prop;
  140. }
  141. /**
  142. * Sets the input data
  143. *
  144. * @param resource|string|array $input
  145. * @return void
  146. */
  147. public function setInput($input) {
  148. if (is_resource($input)) {
  149. $input = stream_get_contents($input);
  150. }
  151. if (is_string($input)) {
  152. $input = json_decode($input);
  153. }
  154. $this->input = $input;
  155. }
  156. }