123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630 |
- <?php
- /**
- * @package Grav\Common\Page
- *
- * @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
- * @license MIT License; see LICENSE file for details.
- */
- namespace Grav\Common\Page;
- use Grav\Common\Grav;
- use Grav\Common\Iterator;
- use Grav\Common\Page\Interfaces\PageInterface;
- use Grav\Common\Utils;
- class Collection extends Iterator
- {
- /**
- * @var Pages
- */
- protected $pages;
- /**
- * @var array
- */
- protected $params;
- /**
- * Collection constructor.
- *
- * @param array $items
- * @param array $params
- * @param Pages|null $pages
- */
- public function __construct($items = [], array $params = [], Pages $pages = null)
- {
- parent::__construct($items);
- $this->params = $params;
- $this->pages = $pages ? $pages : Grav::instance()->offsetGet('pages');
- }
- /**
- * Get the collection params
- *
- * @return array
- */
- public function params()
- {
- return $this->params;
- }
- /**
- * Add a single page to a collection
- *
- * @param PageInterface $page
- *
- * @return $this
- */
- public function addPage(PageInterface $page)
- {
- $this->items[$page->path()] = ['slug' => $page->slug()];
- return $this;
- }
- /**
- * Add a page with path and slug
- *
- * @param string $path
- * @param string $slug
- * @return $this
- */
- public function add($path, $slug)
- {
- $this->items[$path] = ['slug' => $slug];
- return $this;
- }
- /**
- *
- * Create a copy of this collection
- *
- * @return static
- */
- public function copy()
- {
- return new static($this->items, $this->params, $this->pages);
- }
- /**
- *
- * Merge another collection with the current collection
- *
- * @param Collection $collection
- * @return $this
- */
- public function merge(Collection $collection)
- {
- foreach($collection as $page) {
- $this->addPage($page);
- }
- return $this;
- }
- /**
- * Intersect another collection with the current collection
- *
- * @param Collection $collection
- * @return $this
- */
- public function intersect(Collection $collection)
- {
- $array1 = $this->items;
- $array2 = $collection->toArray();
- $this->items = array_uintersect($array1, $array2, function($val1, $val2) {
- return strcmp($val1['slug'], $val2['slug']);
- });
- return $this;
- }
- /**
- * Set parameters to the Collection
- *
- * @param array $params
- *
- * @return $this
- */
- public function setParams(array $params)
- {
- $this->params = array_merge($this->params, $params);
- return $this;
- }
- /**
- * Returns current page.
- *
- * @return PageInterface
- */
- public function current()
- {
- $current = parent::key();
- return $this->pages->get($current);
- }
- /**
- * Returns current slug.
- *
- * @return mixed
- */
- public function key()
- {
- $current = parent::current();
- return $current['slug'];
- }
- /**
- * Returns the value at specified offset.
- *
- * @param mixed $offset The offset to retrieve.
- *
- * @return mixed Can return all value types.
- */
- public function offsetGet($offset)
- {
- return $this->pages->get($offset) ?: null;
- }
- /**
- * Split collection into array of smaller collections.
- *
- * @param int $size
- * @return array|Collection[]
- */
- public function batch($size)
- {
- $chunks = array_chunk($this->items, $size, true);
- $list = [];
- foreach ($chunks as $chunk) {
- $list[] = new static($chunk, $this->params, $this->pages);
- }
- return $list;
- }
- /**
- * Remove item from the list.
- *
- * @param PageInterface|string|null $key
- *
- * @return $this
- * @throws \InvalidArgumentException
- */
- public function remove($key = null)
- {
- if ($key instanceof PageInterface) {
- $key = $key->path();
- } elseif (null === $key) {
- $key = (string)key($this->items);
- }
- if (!\is_string($key)) {
- throw new \InvalidArgumentException('Invalid argument $key.');
- }
- parent::remove($key);
- return $this;
- }
- /**
- * Reorder collection.
- *
- * @param string $by
- * @param string $dir
- * @param array $manual
- * @param string $sort_flags
- *
- * @return $this
- */
- public function order($by, $dir = 'asc', $manual = null, $sort_flags = null)
- {
- $this->items = $this->pages->sortCollection($this, $by, $dir, $manual, $sort_flags);
- return $this;
- }
- /**
- * Check to see if this item is the first in the collection.
- *
- * @param string $path
- *
- * @return bool True if item is first.
- */
- public function isFirst($path)
- {
- return $this->items && $path === array_keys($this->items)[0];
- }
- /**
- * Check to see if this item is the last in the collection.
- *
- * @param string $path
- *
- * @return bool True if item is last.
- */
- public function isLast($path)
- {
- return $this->items && $path === array_keys($this->items)[\count($this->items) - 1];
- }
- /**
- * Gets the previous sibling based on current position.
- *
- * @param string $path
- *
- * @return PageInterface The previous item.
- */
- public function prevSibling($path)
- {
- return $this->adjacentSibling($path, -1);
- }
- /**
- * Gets the next sibling based on current position.
- *
- * @param string $path
- *
- * @return PageInterface The next item.
- */
- public function nextSibling($path)
- {
- return $this->adjacentSibling($path, 1);
- }
- /**
- * Returns the adjacent sibling based on a direction.
- *
- * @param string $path
- * @param int $direction either -1 or +1
- *
- * @return PageInterface|Collection The sibling item.
- */
- public function adjacentSibling($path, $direction = 1)
- {
- $values = array_keys($this->items);
- $keys = array_flip($values);
- if (array_key_exists($path, $keys)) {
- $index = $keys[$path] - $direction;
- return isset($values[$index]) ? $this->offsetGet($values[$index]) : $this;
- }
- return $this;
- }
- /**
- * Returns the item in the current position.
- *
- * @param string $path the path the item
- *
- * @return int the index of the current page.
- */
- public function currentPosition($path)
- {
- return \array_search($path, \array_keys($this->items), true);
- }
- /**
- * Returns the items between a set of date ranges of either the page date field (default) or
- * an arbitrary datetime page field where end date is optional
- * Dates can be passed in as text that strtotime() can process
- * http://php.net/manual/en/function.strtotime.php
- *
- * @param string $startDate
- * @param bool $endDate
- * @param string|null $field
- *
- * @return $this
- * @throws \Exception
- */
- public function dateRange($startDate, $endDate = false, $field = null)
- {
- $start = Utils::date2timestamp($startDate);
- $end = $endDate ? Utils::date2timestamp($endDate) : false;
- $date_range = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null) {
- $date = $field ? strtotime($page->value($field)) : $page->date();
- if ($date >= $start && (!$end || $date <= $end)) {
- $date_range[$path] = $slug;
- }
- }
- }
- $this->items = $date_range;
- return $this;
- }
- /**
- * Creates new collection with only visible pages
- *
- * @return Collection The collection with only visible pages
- */
- public function visible()
- {
- $visible = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->visible()) {
- $visible[$path] = $slug;
- }
- }
- $this->items = $visible;
- return $this;
- }
- /**
- * Creates new collection with only non-visible pages
- *
- * @return Collection The collection with only non-visible pages
- */
- public function nonVisible()
- {
- $visible = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && !$page->visible()) {
- $visible[$path] = $slug;
- }
- }
- $this->items = $visible;
- return $this;
- }
- /**
- * Creates new collection with only modular pages
- *
- * @return Collection The collection with only modular pages
- */
- public function modular()
- {
- $modular = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->modular()) {
- $modular[$path] = $slug;
- }
- }
- $this->items = $modular;
- return $this;
- }
- /**
- * Creates new collection with only non-modular pages
- *
- * @return Collection The collection with only non-modular pages
- */
- public function nonModular()
- {
- $modular = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && !$page->modular()) {
- $modular[$path] = $slug;
- }
- }
- $this->items = $modular;
- return $this;
- }
- /**
- * Creates new collection with only published pages
- *
- * @return Collection The collection with only published pages
- */
- public function published()
- {
- $published = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->published()) {
- $published[$path] = $slug;
- }
- }
- $this->items = $published;
- return $this;
- }
- /**
- * Creates new collection with only non-published pages
- *
- * @return Collection The collection with only non-published pages
- */
- public function nonPublished()
- {
- $published = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && !$page->published()) {
- $published[$path] = $slug;
- }
- }
- $this->items = $published;
- return $this;
- }
- /**
- * Creates new collection with only routable pages
- *
- * @return Collection The collection with only routable pages
- */
- public function routable()
- {
- $routable = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->routable()) {
- $routable[$path] = $slug;
- }
- }
- $this->items = $routable;
- return $this;
- }
- /**
- * Creates new collection with only non-routable pages
- *
- * @return Collection The collection with only non-routable pages
- */
- public function nonRoutable()
- {
- $routable = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && !$page->routable()) {
- $routable[$path] = $slug;
- }
- }
- $this->items = $routable;
- return $this;
- }
- /**
- * Creates new collection with only pages of the specified type
- *
- * @param string $type
- *
- * @return Collection The collection
- */
- public function ofType($type)
- {
- $items = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && $page->template() === $type) {
- $items[$path] = $slug;
- }
- }
- $this->items = $items;
- return $this;
- }
- /**
- * Creates new collection with only pages of one of the specified types
- *
- * @param string[] $types
- *
- * @return Collection The collection
- */
- public function ofOneOfTheseTypes($types)
- {
- $items = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && \in_array($page->template(), $types, true)) {
- $items[$path] = $slug;
- }
- }
- $this->items = $items;
- return $this;
- }
- /**
- * Creates new collection with only pages of one of the specified access levels
- *
- * @param array $accessLevels
- *
- * @return Collection The collection
- */
- public function ofOneOfTheseAccessLevels($accessLevels)
- {
- $items = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null && isset($page->header()->access)) {
- if (\is_array($page->header()->access)) {
- //Multiple values for access
- $valid = false;
- foreach ($page->header()->access as $index => $accessLevel) {
- if (\is_array($accessLevel)) {
- foreach ($accessLevel as $innerIndex => $innerAccessLevel) {
- if (\in_array($innerAccessLevel, $accessLevels)) {
- $valid = true;
- }
- }
- } else {
- if (\in_array($index, $accessLevels)) {
- $valid = true;
- }
- }
- }
- if ($valid) {
- $items[$path] = $slug;
- }
- } else {
- //Single value for access
- if (\in_array($page->header()->access, $accessLevels)) {
- $items[$path] = $slug;
- }
- }
- }
- }
- $this->items = $items;
- return $this;
- }
- /**
- * Get the extended version of this Collection with each page keyed by route
- *
- * @return array
- * @throws \Exception
- */
- public function toExtendedArray()
- {
- $items = [];
- foreach ($this->items as $path => $slug) {
- $page = $this->pages->get($path);
- if ($page !== null) {
- $items[$page->route()] = $page->toArray();
- }
- }
- return $items;
- }
- }
|