AcceptHeader.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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 = [];
  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. * @return self
  42. */
  43. public static function fromString(?string $headerValue)
  44. {
  45. $index = 0;
  46. $parts = HeaderUtils::split($headerValue ?? '', ',;=');
  47. return new self(array_map(function ($subParts) use (&$index) {
  48. $part = array_shift($subParts);
  49. $attributes = HeaderUtils::combine($subParts);
  50. $item = new AcceptHeaderItem($part[0], $attributes);
  51. $item->setIndex($index++);
  52. return $item;
  53. }, $parts));
  54. }
  55. /**
  56. * Returns header value's string representation.
  57. *
  58. * @return string
  59. */
  60. public function __toString()
  61. {
  62. return implode(',', $this->items);
  63. }
  64. /**
  65. * Tests if header has given value.
  66. *
  67. * @return bool
  68. */
  69. public function has(string $value)
  70. {
  71. return isset($this->items[$value]);
  72. }
  73. /**
  74. * Returns given value's item, if exists.
  75. *
  76. * @return AcceptHeaderItem|null
  77. */
  78. public function get(string $value)
  79. {
  80. return $this->items[$value] ?? $this->items[explode('/', $value)[0].'/*'] ?? $this->items['*/*'] ?? $this->items['*'] ?? null;
  81. }
  82. /**
  83. * Adds an item.
  84. *
  85. * @return $this
  86. */
  87. public function add(AcceptHeaderItem $item)
  88. {
  89. $this->items[$item->getValue()] = $item;
  90. $this->sorted = false;
  91. return $this;
  92. }
  93. /**
  94. * Returns all items.
  95. *
  96. * @return AcceptHeaderItem[]
  97. */
  98. public function all()
  99. {
  100. $this->sort();
  101. return $this->items;
  102. }
  103. /**
  104. * Filters items on their value using given regex.
  105. *
  106. * @return self
  107. */
  108. public function filter(string $pattern)
  109. {
  110. return new self(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) {
  111. return preg_match($pattern, $item->getValue());
  112. }));
  113. }
  114. /**
  115. * Returns first item.
  116. *
  117. * @return AcceptHeaderItem|null
  118. */
  119. public function first()
  120. {
  121. $this->sort();
  122. return !empty($this->items) ? reset($this->items) : null;
  123. }
  124. /**
  125. * Sorts items by descending quality.
  126. */
  127. private function sort(): void
  128. {
  129. if (!$this->sorted) {
  130. uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) {
  131. $qA = $a->getQuality();
  132. $qB = $b->getQuality();
  133. if ($qA === $qB) {
  134. return $a->getIndex() > $b->getIndex() ? 1 : -1;
  135. }
  136. return $qA > $qB ? -1 : 1;
  137. });
  138. $this->sorted = true;
  139. }
  140. }
  141. }