/system/src/Grav/Common/Page/Collection.php

https://gitlab.com/asun89/socianovation-web · PHP · 549 lines · 275 code · 77 blank · 197 comment · 45 complexity · c12615925f316de9d3e176f895e935be MD5 · raw file

  1. <?php
  2. namespace Grav\Common\Page;
  3. use Grav\Common\Grav;
  4. use Grav\Common\Iterator;
  5. use Grav\Common\Utils;
  6. /**
  7. * Collection of Pages.
  8. *
  9. * @author RocketTheme
  10. * @license MIT
  11. */
  12. class Collection extends Iterator
  13. {
  14. /**
  15. * @var Pages
  16. */
  17. protected $pages;
  18. /**
  19. * @var array
  20. */
  21. protected $params;
  22. /**
  23. * Collection constructor.
  24. *
  25. * @param array $items
  26. * @param array $params
  27. * @param Pages|null $pages
  28. */
  29. public function __construct($items = [], array $params = [], Pages $pages = null)
  30. {
  31. parent::__construct($items);
  32. $this->params = $params;
  33. $this->pages = $pages ? $pages : Grav::instance()->offsetGet('pages');
  34. }
  35. /**
  36. * Get the collection params
  37. *
  38. * @return array
  39. */
  40. public function params()
  41. {
  42. return $this->params;
  43. }
  44. /**
  45. * Add a single page to a collection
  46. *
  47. * @param Page $page
  48. *
  49. * @return $this
  50. */
  51. public function addPage(Page $page)
  52. {
  53. $this->items[$page->path()] = ['slug' => $page->slug()];
  54. return $this;
  55. }
  56. /**
  57. *
  58. * Create a copy of this collection
  59. *
  60. * @return static
  61. */
  62. public function copy()
  63. {
  64. return new static($this->items, $this->params, $this->pages);
  65. }
  66. /**
  67. * Set parameters to the Collection
  68. *
  69. * @param array $params
  70. *
  71. * @return $this
  72. */
  73. public function setParams(array $params)
  74. {
  75. $this->params = array_merge($this->params, $params);
  76. return $this;
  77. }
  78. /**
  79. * Returns current page.
  80. *
  81. * @return Page
  82. */
  83. public function current()
  84. {
  85. $current = parent::key();
  86. return $this->pages->get($current);
  87. }
  88. /**
  89. * Returns current slug.
  90. *
  91. * @return mixed
  92. */
  93. public function key()
  94. {
  95. $current = parent::current();
  96. return $current['slug'];
  97. }
  98. /**
  99. * Returns the value at specified offset.
  100. *
  101. * @param mixed $offset The offset to retrieve.
  102. *
  103. * @return mixed Can return all value types.
  104. */
  105. public function offsetGet($offset)
  106. {
  107. return !empty($this->items[$offset]) ? $this->pages->get($offset) : null;
  108. }
  109. /**
  110. * Remove item from the list.
  111. *
  112. * @param Page|string|null $key
  113. *
  114. * @return $this|void
  115. * @throws \InvalidArgumentException
  116. */
  117. public function remove($key = null)
  118. {
  119. if ($key instanceof Page) {
  120. $key = $key->path();
  121. } elseif (is_null($key)) {
  122. $key = key($this->items);
  123. }
  124. if (!is_string($key)) {
  125. throw new \InvalidArgumentException('Invalid argument $key.');
  126. }
  127. parent::remove($key);
  128. return $this;
  129. }
  130. /**
  131. * Reorder collection.
  132. *
  133. * @param string $by
  134. * @param string $dir
  135. * @param array $manual
  136. *
  137. * @return $this
  138. */
  139. public function order($by, $dir = 'asc', $manual = null)
  140. {
  141. $this->items = $this->pages->sortCollection($this, $by, $dir, $manual);
  142. return $this;
  143. }
  144. /**
  145. * Check to see if this item is the first in the collection.
  146. *
  147. * @param string $path
  148. *
  149. * @return boolean True if item is first.
  150. */
  151. public function isFirst($path)
  152. {
  153. if ($this->items && $path == array_keys($this->items)[0]) {
  154. return true;
  155. } else {
  156. return false;
  157. }
  158. }
  159. /**
  160. * Check to see if this item is the last in the collection.
  161. *
  162. * @param string $path
  163. *
  164. * @return boolean True if item is last.
  165. */
  166. public function isLast($path)
  167. {
  168. if ($this->items && $path == array_keys($this->items)[count($this->items) - 1]) {
  169. return true;
  170. } else {
  171. return false;
  172. }
  173. }
  174. /**
  175. * Gets the previous sibling based on current position.
  176. *
  177. * @param string $path
  178. *
  179. * @return Page The previous item.
  180. */
  181. public function prevSibling($path)
  182. {
  183. return $this->adjacentSibling($path, -1);
  184. }
  185. /**
  186. * Gets the next sibling based on current position.
  187. *
  188. * @param string $path
  189. *
  190. * @return Page The next item.
  191. */
  192. public function nextSibling($path)
  193. {
  194. return $this->adjacentSibling($path, 1);
  195. }
  196. /**
  197. * Returns the adjacent sibling based on a direction.
  198. *
  199. * @param string $path
  200. * @param integer $direction either -1 or +1
  201. *
  202. * @return Page The sibling item.
  203. */
  204. public function adjacentSibling($path, $direction = 1)
  205. {
  206. $values = array_keys($this->items);
  207. $keys = array_flip($values);
  208. if (array_key_exists($path, $keys)) {
  209. $index = $keys[$path] - $direction;
  210. return isset($values[$index]) ? $this->offsetGet($values[$index]) : $this;
  211. }
  212. return $this;
  213. }
  214. /**
  215. * Returns the item in the current position.
  216. *
  217. * @param string $path the path the item
  218. *
  219. * @return Page Item in the array the the current position.
  220. */
  221. public function currentPosition($path)
  222. {
  223. return array_search($path, array_keys($this->items));
  224. }
  225. /**
  226. * Returns the items between a set of date ranges of either the page date field (default) or
  227. * an arbitrary datetime page field where end date is optional
  228. * Dates can be passed in as text that strtotime() can process
  229. * http://php.net/manual/en/function.strtotime.php
  230. *
  231. * @param $startDate
  232. * @param bool $endDate
  233. * @param $field
  234. *
  235. * @return $this
  236. * @throws \Exception
  237. */
  238. public function dateRange($startDate, $endDate = false, $field = false)
  239. {
  240. $start = Utils::date2timestamp($startDate);
  241. $end = $endDate ? Utils::date2timestamp($endDate) : strtotime("now +1000 years");
  242. $date_range = [];
  243. foreach ($this->items as $path => $slug) {
  244. $page = $this->pages->get($path);
  245. if ($page !== null) {
  246. $date = $field ? strtotime($page->value($field)) : $page->date();
  247. if ($date > $start && $date < $end) {
  248. $date_range[$path] = $slug;
  249. }
  250. }
  251. }
  252. $this->items = $date_range;
  253. return $this;
  254. }
  255. /**
  256. * Creates new collection with only visible pages
  257. *
  258. * @return Collection The collection with only visible pages
  259. */
  260. public function visible()
  261. {
  262. $visible = [];
  263. foreach ($this->items as $path => $slug) {
  264. $page = $this->pages->get($path);
  265. if ($page !== null && $page->visible()) {
  266. $visible[$path] = $slug;
  267. }
  268. }
  269. $this->items = $visible;
  270. return $this;
  271. }
  272. /**
  273. * Creates new collection with only non-visible pages
  274. *
  275. * @return Collection The collection with only non-visible pages
  276. */
  277. public function nonVisible()
  278. {
  279. $visible = [];
  280. foreach ($this->items as $path => $slug) {
  281. $page = $this->pages->get($path);
  282. if ($page !== null && !$page->visible()) {
  283. $visible[$path] = $slug;
  284. }
  285. }
  286. $this->items = $visible;
  287. return $this;
  288. }
  289. /**
  290. * Creates new collection with only modular pages
  291. *
  292. * @return Collection The collection with only modular pages
  293. */
  294. public function modular()
  295. {
  296. $modular = [];
  297. foreach ($this->items as $path => $slug) {
  298. $page = $this->pages->get($path);
  299. if ($page !== null && $page->modular()) {
  300. $modular[$path] = $slug;
  301. }
  302. }
  303. $this->items = $modular;
  304. return $this;
  305. }
  306. /**
  307. * Creates new collection with only non-modular pages
  308. *
  309. * @return Collection The collection with only non-modular pages
  310. */
  311. public function nonModular()
  312. {
  313. $modular = [];
  314. foreach ($this->items as $path => $slug) {
  315. $page = $this->pages->get($path);
  316. if ($page !== null && !$page->modular()) {
  317. $modular[$path] = $slug;
  318. }
  319. }
  320. $this->items = $modular;
  321. return $this;
  322. }
  323. /**
  324. * Creates new collection with only published pages
  325. *
  326. * @return Collection The collection with only published pages
  327. */
  328. public function published()
  329. {
  330. $published = [];
  331. foreach ($this->items as $path => $slug) {
  332. $page = $this->pages->get($path);
  333. if ($page !== null && $page->published()) {
  334. $published[$path] = $slug;
  335. }
  336. }
  337. $this->items = $published;
  338. return $this;
  339. }
  340. /**
  341. * Creates new collection with only non-published pages
  342. *
  343. * @return Collection The collection with only non-published pages
  344. */
  345. public function nonPublished()
  346. {
  347. $published = [];
  348. foreach ($this->items as $path => $slug) {
  349. $page = $this->pages->get($path);
  350. if ($page !== null && !$page->published()) {
  351. $published[$path] = $slug;
  352. }
  353. }
  354. $this->items = $published;
  355. return $this;
  356. }
  357. /**
  358. * Creates new collection with only routable pages
  359. *
  360. * @return Collection The collection with only routable pages
  361. */
  362. public function routable()
  363. {
  364. $routable = [];
  365. foreach ($this->items as $path => $slug) {
  366. $page = $this->pages->get($path);
  367. if ($page !== null && $page->routable()) {
  368. $routable[$path] = $slug;
  369. }
  370. }
  371. $this->items = $routable;
  372. return $this;
  373. }
  374. /**
  375. * Creates new collection with only non-routable pages
  376. *
  377. * @return Collection The collection with only non-routable pages
  378. */
  379. public function nonRoutable()
  380. {
  381. $routable = [];
  382. foreach ($this->items as $path => $slug) {
  383. $page = $this->pages->get($path);
  384. if ($page !== null && !$page->routable()) {
  385. $routable[$path] = $slug;
  386. }
  387. }
  388. $this->items = $routable;
  389. return $this;
  390. }
  391. /**
  392. * Creates new collection with only pages of the specified type
  393. *
  394. * @param $type
  395. *
  396. * @return Collection The collection
  397. */
  398. public function ofType($type)
  399. {
  400. $items = [];
  401. foreach ($this->items as $path => $slug) {
  402. $page = $this->pages->get($path);
  403. if ($page !== null && $page->template() == $type) {
  404. $items[$path] = $slug;
  405. }
  406. }
  407. $this->items = $items;
  408. return $this;
  409. }
  410. /**
  411. * Creates new collection with only pages of one of the specified types
  412. *
  413. * @param $types
  414. *
  415. * @return Collection The collection
  416. */
  417. public function ofOneOfTheseTypes($types)
  418. {
  419. $items = [];
  420. foreach ($this->items as $path => $slug) {
  421. $page = $this->pages->get($path);
  422. if ($page !== null && in_array($page->template(), $types)) {
  423. $items[$path] = $slug;
  424. }
  425. }
  426. $this->items = $items;
  427. return $this;
  428. }
  429. /**
  430. * Creates new collection with only pages of one of the specified access levels
  431. *
  432. * @param $accessLevels
  433. *
  434. * @return Collection The collection
  435. */
  436. public function ofOneOfTheseAccessLevels($accessLevels)
  437. {
  438. $items = [];
  439. foreach ($this->items as $path => $slug) {
  440. $page = $this->pages->get($path);
  441. if ($page !== null && isset($page->header()->access)) {
  442. if (is_array($page->header()->access)) {
  443. //Multiple values for access
  444. $valid = false;
  445. foreach ($page->header()->access as $index => $accessLevel) {
  446. if (is_array($accessLevel)) {
  447. foreach ($accessLevel as $innerIndex => $innerAccessLevel) {
  448. if (in_array($innerAccessLevel, $accessLevels)) {
  449. $valid = true;
  450. }
  451. }
  452. } else {
  453. if (in_array($index, $accessLevels)) {
  454. $valid = true;
  455. }
  456. }
  457. }
  458. if ($valid) {
  459. $items[$path] = $slug;
  460. }
  461. } else {
  462. //Single value for access
  463. if (in_array($page->header()->access, $accessLevels)) {
  464. $items[$path] = $slug;
  465. }
  466. }
  467. }
  468. }
  469. $this->items = $items;
  470. return $this;
  471. }
  472. }