AcceptHeader.php 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpFoundation;
  11. /**
  12. * Represents an Accept-* header.
  13. *
  14. * An accept header is compound with a list of items,
  15. * sorted by descending quality.
  16. *
  17. * @author Jean-François Simon <contact@jfsimon.fr>
  18. */
  19. class AcceptHeader
  20. {
  21. /**
  22. * @var AcceptHeaderItem[]
  23. */
  24. private $items = array();
  25. /**
  26. * @var bool
  27. */
  28. private $sorted = true;
  29. /**
  30. * @param AcceptHeaderItem[] $items
  31. */
  32. public function __construct(array $items)
  33. {
  34. foreach ($items as $item) {
  35. $this->add($item);
  36. }
  37. }
  38. /**
  39. * Builds an AcceptHeader instance from a string.
  40. *
  41. * @param string $headerValue
  42. *
  43. * @return self
  44. */
  45. public static function fromString($headerValue)
  46. {
  47. $index = 0;
  48. $parts = HeaderUtils::split((string) $headerValue, ',;=');
  49. return new self(array_map(function ($subParts) use (&$index) {
  50. $part = array_shift($subParts);
  51. $attributes = HeaderUtils::combine($subParts);
  52. $item = new AcceptHeaderItem($part[0], $attributes);
  53. $item->setIndex($index++);
  54. return $item;
  55. }, $parts));
  56. }
  57. /**
  58. * Returns header value's string representation.
  59. *
  60. * @return string
  61. */
  62. public function __toString()
  63. {
  64. return implode(',', $this->items);
  65. }
  66. /**
  67. * Tests if header has given value.
  68. *
  69. * @param string $value
  70. *
  71. * @return bool
  72. */
  73. public function has($value)
  74. {
  75. return isset($this->items[$value]);
  76. }
  77. /**
  78. * Returns given value's item, if exists.
  79. *
  80. * @param string $value
  81. *
  82. * @return AcceptHeaderItem|null
  83. */
  84. public function get($value)
  85. {
  86. return $this->items[$value] ?? $this->items[explode('/', $value)[0].'/*'] ?? $this->items['*/*'] ?? $this->items['*'] ?? null;
  87. }
  88. /**
  89. * Adds an item.
  90. *
  91. * @return $this
  92. */
  93. public function add(AcceptHeaderItem $item)
  94. {
  95. $this->items[$item->getValue()] = $item;
  96. $this->sorted = false;
  97. return $this;
  98. }
  99. /**
  100. * Returns all items.
  101. *
  102. * @return AcceptHeaderItem[]
  103. */
  104. public function all()
  105. {
  106. $this->sort();
  107. return $this->items;
  108. }
  109. /**
  110. * Filters items on their value using given regex.
  111. *
  112. * @param string $pattern
  113. *
  114. * @return self
  115. */
  116. public function filter($pattern)
  117. {
  118. return new self(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) {
  119. return preg_match($pattern, $item->getValue());
  120. }));
  121. }
  122. /**
  123. * Returns first item.
  124. *
  125. * @return AcceptHeaderItem|null
  126. */
  127. public function first()
  128. {
  129. $this->sort();
  130. return !empty($this->items) ? reset($this->items) : null;
  131. }
  132. /**
  133. * Sorts items by descending quality.
  134. */
  135. private function sort()
  136. {
  137. if (!$this->sorted) {
  138. uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) {
  139. $qA = $a->getQuality();
  140. $qB = $b->getQuality();
  141. if ($qA === $qB) {
  142. return $a->getIndex() > $b->getIndex() ? 1 : -1;
  143. }
  144. return $qA > $qB ? -1 : 1;
  145. });
  146. $this->sorted = true;
  147. }
  148. }
  149. }