FlexPageCollection.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @package Grav\Framework\Flex
  5. *
  6. * @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
  7. * @license MIT License; see LICENSE file for details.
  8. */
  9. namespace Grav\Framework\Flex\Pages;
  10. use Grav\Common\Page\Interfaces\PageInterface;
  11. use Grav\Framework\Flex\FlexCollection;
  12. use function array_search;
  13. use function assert;
  14. use function is_int;
  15. /**
  16. * Class FlexPageCollection
  17. * @package Grav\Plugin\FlexObjects\Types\FlexPages
  18. * @template T of \Grav\Framework\Flex\Interfaces\FlexObjectInterface
  19. * @extends FlexCollection<T>
  20. */
  21. class FlexPageCollection extends FlexCollection
  22. {
  23. /**
  24. * @return array
  25. */
  26. public static function getCachedMethods(): array
  27. {
  28. return [
  29. // Collection filtering
  30. 'withPublished' => true,
  31. 'withVisible' => true,
  32. 'withRoutable' => true,
  33. 'isFirst' => true,
  34. 'isLast' => true,
  35. // Find objects
  36. 'prevSibling' => false,
  37. 'nextSibling' => false,
  38. 'adjacentSibling' => false,
  39. 'currentPosition' => true,
  40. 'getNextOrder' => false,
  41. ] + parent::getCachedMethods();
  42. }
  43. /**
  44. * @param bool $bool
  45. * @return static
  46. * @phpstan-return static<T>
  47. */
  48. public function withPublished(bool $bool = true)
  49. {
  50. $list = array_keys(array_filter($this->call('isPublished', [$bool])));
  51. return $this->select($list);
  52. }
  53. /**
  54. * @param bool $bool
  55. * @return static
  56. * @phpstan-return static<T>
  57. */
  58. public function withVisible(bool $bool = true)
  59. {
  60. $list = array_keys(array_filter($this->call('isVisible', [$bool])));
  61. return $this->select($list);
  62. }
  63. /**
  64. * @param bool $bool
  65. * @return static
  66. * @phpstan-return static<T>
  67. */
  68. public function withRoutable(bool $bool = true)
  69. {
  70. $list = array_keys(array_filter($this->call('isRoutable', [$bool])));
  71. return $this->select($list);
  72. }
  73. /**
  74. * Check to see if this item is the first in the collection.
  75. *
  76. * @param string $path
  77. * @return bool True if item is first.
  78. */
  79. public function isFirst($path): bool
  80. {
  81. $keys = $this->getKeys();
  82. $first = reset($keys);
  83. return $path === $first;
  84. }
  85. /**
  86. * Check to see if this item is the last in the collection.
  87. *
  88. * @param string $path
  89. * @return bool True if item is last.
  90. */
  91. public function isLast($path): bool
  92. {
  93. $keys = $this->getKeys();
  94. $last = end($keys);
  95. return $path === $last;
  96. }
  97. /**
  98. * Gets the previous sibling based on current position.
  99. *
  100. * @param string $path
  101. * @return PageInterface|false The previous item.
  102. * @phpstan-return T|false
  103. */
  104. public function prevSibling($path)
  105. {
  106. return $this->adjacentSibling($path, -1);
  107. }
  108. /**
  109. * Gets the next sibling based on current position.
  110. *
  111. * @param string $path
  112. * @return PageInterface|false The next item.
  113. * @phpstan-return T|false
  114. */
  115. public function nextSibling($path)
  116. {
  117. return $this->adjacentSibling($path, 1);
  118. }
  119. /**
  120. * Returns the adjacent sibling based on a direction.
  121. *
  122. * @param string $path
  123. * @param int $direction either -1 or +1
  124. * @return PageInterface|false The sibling item.
  125. * @phpstan-return T|false
  126. */
  127. public function adjacentSibling($path, $direction = 1)
  128. {
  129. $keys = $this->getKeys();
  130. $pos = array_search($path, $keys, true);
  131. if ($pos !== false) {
  132. $pos += $direction;
  133. if (isset($keys[$pos])) {
  134. return $this[$keys[$pos]];
  135. }
  136. }
  137. return false;
  138. }
  139. /**
  140. * Returns the item in the current position.
  141. *
  142. * @param string $path the path the item
  143. * @return int|null The index of the current page, null if not found.
  144. */
  145. public function currentPosition($path): ?int
  146. {
  147. $pos = array_search($path, $this->getKeys(), true);
  148. return $pos !== false ? $pos : null;
  149. }
  150. /**
  151. * @return string
  152. */
  153. public function getNextOrder()
  154. {
  155. $directory = $this->getFlexDirectory();
  156. $collection = $directory->getIndex();
  157. $keys = $collection->getStorageKeys();
  158. // Assign next free order.
  159. /** @var FlexPageObject|null $last */
  160. $last = null;
  161. $order = 0;
  162. foreach ($keys as $folder => $key) {
  163. preg_match(FlexPageIndex::ORDER_PREFIX_REGEX, $folder, $test);
  164. $test = $test[0] ?? null;
  165. if ($test && $test > $order) {
  166. $order = $test;
  167. $last = $key;
  168. }
  169. }
  170. $last = $collection[$last];
  171. return sprintf('%d.', $last ? $last->value('order') + 1 : 1);
  172. }
  173. }