PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/kirby/core/pages.php

https://gitlab.com/gricelya/rental
PHP | 330 lines | 170 code | 67 blank | 93 comment | 31 complexity | 6acb8098393ecfb2c2f39eca60386567 MD5 | raw file
  1. <?php
  2. /**
  3. * Pages
  4. *
  5. * @package Kirby CMS
  6. * @author Bastian Allgeier <bastian@getkirby.com>
  7. * @link http://getkirby.com
  8. * @copyright Bastian Allgeier
  9. * @license http://getkirby.com/license
  10. */
  11. abstract class PagesAbstract extends Collection {
  12. static public $methods = array();
  13. /**
  14. * Constructor
  15. */
  16. public function __construct($data = array()) {
  17. foreach($data as $object) {
  18. $this->add($object);
  19. }
  20. }
  21. public function __call($method, $arguments) {
  22. if(isset(static::$methods[$method])) {
  23. array_unshift($arguments, clone $this);
  24. return call(static::$methods[$method], $arguments);
  25. } else {
  26. return $this->get($method);
  27. }
  28. }
  29. /**
  30. * Adds a single page object to the
  31. * collection by id or the entire object
  32. *
  33. * @param mixed $page
  34. */
  35. public function add($page) {
  36. if(is_a($page, 'Collection')) {
  37. foreach($page as $object) $this->add($object);
  38. } else if(is_string($page) and $object = page($page)) {
  39. $this->data[$object->id()] = $object;
  40. } else if(is_a($page, 'Page')) {
  41. $this->data[$page->id()] = $page;
  42. }
  43. return $this;
  44. }
  45. /**
  46. * Returns a new collection of pages without the given pages
  47. *
  48. * @param args any number of uris or page elements, passed as individual arguments
  49. * @return object a new collection without the pages
  50. */
  51. public function not() {
  52. $collection = clone $this;
  53. foreach(func_get_args() as $uri) {
  54. if(is_array($uri) or $uri instanceof Traversable) {
  55. foreach($uri as $u) {
  56. $collection = $collection->not($u);
  57. }
  58. } else if(is_a($uri, 'Page')) {
  59. // unset by Page object
  60. unset($collection->data[$uri->id()]);
  61. } else if(isset($collection->data[$uri])) {
  62. // unset by URI
  63. unset($collection->data[$uri]);
  64. } else if($page = $collection->findBy('uid', $uri)) {
  65. // unset by UID
  66. unset($collection->data[$page->id()]);
  67. }
  68. }
  69. return $collection;
  70. }
  71. public function find() {
  72. $args = func_get_args();
  73. if(count($args) === 1 and is_array($args[0])) {
  74. $args = $args[0];
  75. }
  76. if(!count($args)) {
  77. return false;
  78. }
  79. if(count($args) > 1) {
  80. $pages = new static();
  81. foreach($args as $id) {
  82. if($page = $this->find($id)) {
  83. $pages->data[$page->id()] = $page;
  84. }
  85. }
  86. return $pages;
  87. } else {
  88. // get the first argument and remove slashes
  89. $id = trim($args[0], '/');
  90. // fast access to direct uris
  91. return isset($this->data[$id]) ? $this->data[$id] : null;
  92. }
  93. }
  94. /**
  95. * Find a single page by a given value
  96. *
  97. * @param string $field
  98. * @param string $value
  99. * @return Page
  100. */
  101. public function findBy($field, $value) {
  102. foreach($this->data as $page) {
  103. if($page->$field() == $value) return $page;
  104. }
  105. return false;
  106. }
  107. /**
  108. * Find the open page in a set
  109. *
  110. * @return Page
  111. */
  112. public function findOpen() {
  113. return $this->findBy('isOpen', true);
  114. }
  115. /**
  116. * Filters the collection by visible pages
  117. *
  118. * @return Children
  119. */
  120. public function visible() {
  121. $collection = clone $this;
  122. return $collection->filterBy('isVisible', true);
  123. }
  124. /**
  125. * Filters the collection by invisible pages
  126. *
  127. * @return Children
  128. */
  129. public function invisible() {
  130. $collection = clone $this;
  131. return $collection->filterBy('isInvisible', true);
  132. }
  133. /**
  134. * Checks if a page is in a set of children
  135. *
  136. * @param Page | string $page
  137. * @return boolean
  138. */
  139. public function has($page) {
  140. $uri = is_string($page) ? $page : $page->id();
  141. return parent::has($uri);
  142. }
  143. /**
  144. * Native search method to search for anything within the collection
  145. */
  146. public function search($query, $params = array()) {
  147. if(is_string($params)) {
  148. $params = array('fields' => str::split($params, '|'));
  149. }
  150. $defaults = array(
  151. 'minlength' => 2,
  152. 'fields' => array(),
  153. 'words' => false,
  154. 'score' => array()
  155. );
  156. $options = array_merge($defaults, $params);
  157. $collection = clone $this;
  158. $searchwords = preg_replace('/(\s)/u',',', $query);
  159. $searchwords = str::split($searchwords, ',', $options['minlength']);
  160. if(!empty($options['stopwords'])) {
  161. $searchwords = array_diff($searchwords, $options['stopwords']);
  162. }
  163. if(empty($searchwords)) return $collection->limit(0);
  164. $searchwords = array_map(function($value) use($options) {
  165. return $options['words'] ? '\b' . preg_quote($value) . '\b' : preg_quote($value);
  166. }, $searchwords);
  167. $preg = '!(' . implode('|', $searchwords) . ')!i';
  168. $results = $collection->filter(function($page) use($query, $searchwords, $preg, $options) {
  169. $data = $page->content()->toArray();
  170. $keys = array_keys($data);
  171. if(!empty($options['fields'])) {
  172. $keys = array_intersect($keys, $options['fields']);
  173. }
  174. $page->searchHits = 0;
  175. $page->searchScore = 0;
  176. foreach($keys as $key) {
  177. $score = a::get($options['score'], $key, 1);
  178. // check for a match
  179. if($matches = preg_match_all($preg, $data[$key], $r)) {
  180. $page->searchHits += $matches;
  181. $page->searchScore += $matches * $score;
  182. // check for full matches
  183. if($matches = preg_match_all('!' . preg_quote($query) . '!i', $data[$key], $r)) {
  184. $page->searchScore += $matches * $score;
  185. }
  186. }
  187. }
  188. return $page->searchHits > 0 ? true : false;
  189. });
  190. $results = $results->sortBy('searchScore', SORT_DESC);
  191. return $results;
  192. }
  193. /**
  194. * Returns files from all pages
  195. *
  196. * @return object A collection of all files of the pages (not of their subpages)
  197. */
  198. public function files() {
  199. $files = new Collection();
  200. foreach($this->data as $page) {
  201. foreach($page->files() as $file) {
  202. $files->append($page->id() . '/' . strtolower($file->filename()), $file);
  203. }
  204. }
  205. return $files;
  206. }
  207. // File type filters
  208. public function images() { return $this->files()->filterBy('type', 'image'); }
  209. public function videos() { return $this->files()->filterBy('type', 'video'); }
  210. public function documents() { return $this->files()->filterBy('type', 'document'); }
  211. public function audio() { return $this->files()->filterBy('type', 'audio'); }
  212. public function code() { return $this->files()->filterBy('type', 'code'); }
  213. public function archives() { return $this->files()->filterBy('type', 'archive'); }
  214. /**
  215. * Groups the pages by a given field
  216. *
  217. * @param string $field
  218. * @param bool $i (ignore upper/lowercase for group names)
  219. * @return object A collection with an item for each group and a Pages object for each group
  220. */
  221. public function groupBy($field, $i = true) {
  222. $groups = array();
  223. foreach($this->data as $key => $item) {
  224. $value = $item->content()->get($field)->value();
  225. // make sure that there's always a proper value to group by
  226. if(!$value) throw new Exception('Invalid grouping value for key: ' . $key);
  227. // ignore upper/lowercase for group names
  228. if($i) $value = str::lower($value);
  229. if(!isset($groups[$value])) {
  230. // create a new entry for the group if it does not exist yet
  231. $groups[$value] = new Pages(array($key => $item));
  232. } else {
  233. // add the item to an existing group
  234. $groups[$value]->set($key, $item);
  235. }
  236. }
  237. return new Collection($groups);
  238. }
  239. /**
  240. * Converts the pages collection
  241. * into a plain array
  242. *
  243. * @param closure $callback Filter callback for each item
  244. * @return array
  245. */
  246. public function toArray($callback = null) {
  247. $data = array();
  248. foreach($this as $page) {
  249. $data[] = is_string($page) ? $page : $page->toArray($callback);
  250. }
  251. return $data;
  252. }
  253. /**
  254. * Converts the pages collection
  255. * into a json string
  256. *
  257. * @param closure $callback Filter callback for each item
  258. * @return string
  259. */
  260. public function toJson($callback = null) {
  261. return json_encode($this->toArray($callback));
  262. }
  263. }