GraphNode.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <?php
  2. /**
  3. * Copyright 2016 Facebook, Inc.
  4. *
  5. * You are hereby granted a non-exclusive, worldwide, royalty-free license to
  6. * use, copy, modify, and distribute this software in source code or binary
  7. * form for use in connection with the web services and APIs provided by
  8. * Facebook.
  9. *
  10. * As with any software that integrates with the Facebook platform, your use
  11. * of this software is subject to the Facebook Developer Principles and
  12. * Policies [http://developers.facebook.com/policy/]. This copyright notice
  13. * shall be included in all copies or substantial portions of the software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21. * DEALINGS IN THE SOFTWARE.
  22. *
  23. */
  24. namespace Facebook\GraphNodes;
  25. /**
  26. * Class GraphNode
  27. *
  28. * @package Facebook
  29. */
  30. class GraphNode extends Collection
  31. {
  32. /**
  33. * @var array Maps object key names to Graph object types.
  34. */
  35. protected static $graphObjectMap = [];
  36. /**
  37. * Init this Graph object.
  38. *
  39. * @param array $data
  40. */
  41. public function __construct(array $data = [])
  42. {
  43. parent::__construct($this->castItems($data));
  44. }
  45. /**
  46. * Iterates over an array and detects the types each node
  47. * should be cast to and returns all the items as an array.
  48. *
  49. * @TODO Add auto-casting to AccessToken entities.
  50. *
  51. * @param array $data The array to iterate over.
  52. *
  53. * @return array
  54. */
  55. public function castItems(array $data)
  56. {
  57. $items = [];
  58. foreach ($data as $k => $v) {
  59. if ($this->shouldCastAsDateTime($k)
  60. && (is_numeric($v)
  61. || $this->isIso8601DateString($v))
  62. ) {
  63. $items[$k] = $this->castToDateTime($v);
  64. } elseif ($k === 'birthday') {
  65. $items[$k] = $this->castToBirthday($v);
  66. } else {
  67. $items[$k] = $v;
  68. }
  69. }
  70. return $items;
  71. }
  72. /**
  73. * Uncasts any auto-casted datatypes.
  74. * Basically the reverse of castItems().
  75. *
  76. * @return array
  77. */
  78. public function uncastItems()
  79. {
  80. $items = $this->asArray();
  81. return array_map(function ($v) {
  82. if ($v instanceof \DateTime) {
  83. return $v->format(\DateTime::ISO8601);
  84. }
  85. return $v;
  86. }, $items);
  87. }
  88. /**
  89. * Get the collection of items as JSON.
  90. *
  91. * @param int $options
  92. *
  93. * @return string
  94. */
  95. public function asJson($options = 0)
  96. {
  97. return json_encode($this->uncastItems(), $options);
  98. }
  99. /**
  100. * Detects an ISO 8601 formatted string.
  101. *
  102. * @param string $string
  103. *
  104. * @return boolean
  105. *
  106. * @see https://developers.facebook.com/docs/graph-api/using-graph-api/#readmodifiers
  107. * @see http://www.cl.cam.ac.uk/~mgk25/iso-time.html
  108. * @see http://en.wikipedia.org/wiki/ISO_8601
  109. */
  110. public function isIso8601DateString($string)
  111. {
  112. // This insane regex was yoinked from here:
  113. // http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/
  114. // ...and I'm all like:
  115. // http://thecodinglove.com/post/95378251969/when-code-works-and-i-dont-know-why
  116. $crazyInsaneRegexThatSomehowDetectsIso8601 = '/^([\+-]?\d{4}(?!\d{2}\b))'
  117. . '((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?'
  118. . '|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d'
  119. . '|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])'
  120. . '((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d'
  121. . '([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/';
  122. return preg_match($crazyInsaneRegexThatSomehowDetectsIso8601, $string) === 1;
  123. }
  124. /**
  125. * Determines if a value from Graph should be cast to DateTime.
  126. *
  127. * @param string $key
  128. *
  129. * @return boolean
  130. */
  131. public function shouldCastAsDateTime($key)
  132. {
  133. return in_array($key, [
  134. 'created_time',
  135. 'updated_time',
  136. 'start_time',
  137. 'end_time',
  138. 'backdated_time',
  139. 'issued_at',
  140. 'expires_at',
  141. 'publish_time'
  142. ], true);
  143. }
  144. /**
  145. * Casts a date value from Graph to DateTime.
  146. *
  147. * @param int|string $value
  148. *
  149. * @return \DateTime
  150. */
  151. public function castToDateTime($value)
  152. {
  153. if (is_int($value)) {
  154. $dt = new \DateTime();
  155. $dt->setTimestamp($value);
  156. } else {
  157. $dt = new \DateTime($value);
  158. }
  159. return $dt;
  160. }
  161. /**
  162. * Casts a birthday value from Graph to Birthday
  163. *
  164. * @param string $value
  165. *
  166. * @return Birthday
  167. */
  168. public function castToBirthday($value)
  169. {
  170. return new Birthday($value);
  171. }
  172. /**
  173. * Getter for $graphObjectMap.
  174. *
  175. * @return array
  176. */
  177. public static function getObjectMap()
  178. {
  179. return static::$graphObjectMap;
  180. }
  181. }