PageRenderTime 145ms CodeModel.GetById 57ms RepoModel.GetById 1ms app.codeStats 0ms

/concrete/core/models/page_list.php

https://bitbucket.org/selfeky/xclusivescardwebsite
PHP | 541 lines | 376 code | 70 blank | 95 comment | 74 complexity | 3fc69dda4a9242f39bb8ef5570c44bc7 MD5 | raw file
  1. <?php
  2. defined('C5_EXECUTE') or die("Access Denied.");
  3. /**
  4. *
  5. * An object that allows a filtered list of pages to be returned.
  6. * @package Pages
  7. *
  8. */
  9. class Concrete5_Model_PageList extends DatabaseItemList {
  10. protected $includeSystemPages = false;
  11. protected $attributeFilters = array();
  12. protected $includeAliases = true;
  13. protected $displayOnlyPermittedPages = false; // not used.
  14. protected $displayOnlyApprovedPages = true;
  15. protected $displayOnlyActivePages = true;
  16. protected $filterByCParentID = 0;
  17. protected $filterByCT = false;
  18. protected $ignorePermissions = false;
  19. protected $attributeClass = 'CollectionAttributeKey';
  20. protected $autoSortColumns = array('cvName', 'cvDatePublic', 'cDateAdded', 'cDateModified');
  21. protected $indexedSearch = false;
  22. protected $viewPagePermissionKeyHandle = 'view_page';
  23. /* magic method for filtering by page attributes. */
  24. public function __call($nm, $a) {
  25. if (substr($nm, 0, 8) == 'filterBy') {
  26. $txt = Loader::helper('text');
  27. $attrib = $txt->uncamelcase(substr($nm, 8));
  28. if (count($a) == 2) {
  29. $this->filterByAttribute($attrib, $a[0], $a[1]);
  30. } else {
  31. $this->filterByAttribute($attrib, $a[0]);
  32. }
  33. }
  34. }
  35. public function setViewPagePermissionKeyHandle($pkHandle) {
  36. $this->viewPagePermissionKeyHandle = $pkHandle;
  37. }
  38. public function includeInactivePages() {
  39. $this->displayOnlyActivePages = false;
  40. }
  41. public function ignorePermissions() {
  42. $this->ignorePermissions = true;
  43. }
  44. public function ignoreAliases() {
  45. $this->includeAliases = false;
  46. }
  47. public function includeSystemPages() {
  48. $this->includeSystemPages = true;
  49. }
  50. public function displayUnapprovedPages() {
  51. $this->displayOnlyApprovedPages = false;
  52. }
  53. public function isIndexedSearch() {return $this->indexedSearch;}
  54. /**
  55. * Filters by "keywords" (which searches everything including filenames, title, tags, users who uploaded the file, tags)
  56. */
  57. public function filterByKeywords($keywords, $simple = false) {
  58. $db = Loader::db();
  59. $kw = $db->quote($keywords);
  60. $qk = $db->quote('%' . $keywords . '%');
  61. Loader::model('attribute/categories/collection');
  62. $keys = CollectionAttributeKey::getSearchableIndexedList();
  63. $attribsStr = '';
  64. foreach ($keys as $ak) {
  65. $cnt = $ak->getController();
  66. $attribsStr.=' OR ' . $cnt->searchKeywords($keywords);
  67. }
  68. if ($simple || $this->indexModeSimple) { // $this->indexModeSimple is set by the IndexedPageList class
  69. $this->filter(false, "(psi.cName like $qk or psi.cDescription like $qk or psi.content like $qk {$attribsStr})");
  70. } else {
  71. $this->indexedSearch = true;
  72. $this->indexedKeywords = $keywords;
  73. $this->autoSortColumns[] = 'cIndexScore';
  74. $this->filter(false, "((match(psi.cName, psi.cDescription, psi.content) against ({$kw})) {$attribsStr})");
  75. }
  76. }
  77. public function filterByName($name, $exact = false) {
  78. if ($exact) {
  79. $this->filter('cvName', $name, '=');
  80. } else {
  81. $this->filter('cvName', '%' . $name . '%', 'like');
  82. }
  83. }
  84. public function filterByPath($path, $includeAllChildren = true) {
  85. if (!$includeAllChildren) {
  86. $this->filter('PagePaths.cPath', $path, '=');
  87. } else {
  88. $this->filter('PagePaths.cPath', $path . '/%', 'like');
  89. }
  90. $this->filter('PagePaths.ppIsCanonical', 1);
  91. }
  92. /**
  93. * Sets up a list to only return items the proper user can access
  94. */
  95. public function setupPermissions() {
  96. $u = new User();
  97. if ($u->isSuperUser() || ($this->ignorePermissions)) {
  98. return; // super user always sees everything. no need to limit
  99. }
  100. $accessEntities = $u->getUserAccessEntityObjects();
  101. foreach($accessEntities as $pae) {
  102. $peIDs[] = $pae->getAccessEntityID();
  103. }
  104. $owpae = PageOwnerPermissionAccessEntity::getOrCreate();
  105. // now we retrieve a list of permission duration object IDs that are attached view_page or view_page_version
  106. // against any of these access entity objects. We just get'em all.
  107. $db = Loader::db();
  108. $activePDIDs = array();
  109. $vpPKID = $db->GetOne('select pkID from PermissionKeys where pkHandle = ?', array($this->viewPagePermissionKeyHandle));
  110. /*
  111. $vpvPKID = $db->GetOne('select pkID from PermissionKeys where pkHandle = \'view_page_versions\'');
  112. $pdIDs = $db->GetCol("select distinct pdID from PagePermissionAssignments ppa inner join PermissionAccessList pa on ppa.paID = pa.paID where pkID in (?, ?) and pdID > 0", array($vpPKID, $vpvPKID));
  113. */
  114. $pdIDs = $db->GetCol("select distinct pdID from PagePermissionAssignments ppa inner join PermissionAccessList pa on ppa.paID = pa.paID where pkID =? and pdID > 0", array($vpPKID));
  115. if (count($pdIDs) > 0) {
  116. // then we iterate through all of them and find any that are active RIGHT NOW
  117. foreach($pdIDs as $pdID) {
  118. $pd = PermissionDuration::getByID($pdID);
  119. if ($pd->isActive()) {
  120. $activePDIDs[] = $pd->getPermissionDurationID();
  121. }
  122. }
  123. }
  124. $activePDIDs[] = 0;
  125. if ($this->includeAliases) {
  126. $cInheritPermissionsFromCID = 'if(p2.cID is null, p1.cInheritPermissionsFromCID, p2.cInheritPermissionsFromCID)';
  127. } else {
  128. $cInheritPermissionsFromCID = 'p1.cInheritPermissionsFromCID';
  129. }
  130. if ($this->displayOnlyApprovedPages) {
  131. $cvIsApproved = ' and cv.cvIsApproved = 1';
  132. }
  133. $uID = 0;
  134. if ($u->isRegistered()) {
  135. $uID = $u->getUserID();
  136. }
  137. /*
  138. $this->filter(false, "((select count(cID) from PagePermissionAssignments ppa1 inner join PermissionAccessList pa1 on ppa1.paID = pa1.paID where ppa1.cID = {$cInheritPermissionsFromCID} and pa1.accessType = " . PermissionKey::ACCESS_TYPE_INCLUDE . " and pa1.pdID in (" . implode(',', $activePDIDs) . ")
  139. and pa1.peID in (" . implode(',', $peIDs) . ") and (if(pa1.peID = " . $owpae->getAccessEntityID() . " and p1.uID <>" . $uID . ", false, true)) and (ppa1.pkID = " . $vpPKID . $cvIsApproved . " or ppa1.pkID = " . $vpvPKID . ")) > 0
  140. or (p1.cPointerExternalLink !='' AND p1.cPointerExternalLink IS NOT NULL))");
  141. $this->filter(false, "((select count(cID) from PagePermissionAssignments ppaExclude inner join PermissionAccessList paExclude on ppaExclude.paID = paExclude.paID where ppaExclude.cID = {$cInheritPermissionsFromCID} and accessType = " . PermissionKey::ACCESS_TYPE_EXCLUDE . " and pdID in (" . implode(',', $activePDIDs) . ")
  142. and paExclude.peID in (" . implode(',', $peIDs) . ") and (if(paExclude.peID = " . $owpae->getAccessEntityID() . " and p1.uID <>" . $uID . ", false, true)) and (ppaExclude.pkID = " . $vpPKID . $cvIsApproved . " or ppaExclude.pkID = " . $vpvPKID . ")) = 0)");
  143. */
  144. $this->filter(false, "((select count(cID) from PagePermissionAssignments ppa1 inner join PermissionAccessList pa1 on ppa1.paID = pa1.paID where ppa1.cID = {$cInheritPermissionsFromCID} and pa1.accessType = " . PermissionKey::ACCESS_TYPE_INCLUDE . " and pa1.pdID in (" . implode(',', $activePDIDs) . ")
  145. and pa1.peID in (" . implode(',', $peIDs) . ") and (if(pa1.peID = " . $owpae->getAccessEntityID() . " and p1.uID <>" . $uID . ", false, true)) and (ppa1.pkID = " . $vpPKID . $cvIsApproved . ")) > 0
  146. or (p1.cPointerExternalLink !='' AND p1.cPointerExternalLink IS NOT NULL))");
  147. $this->filter(false, "((select count(cID) from PagePermissionAssignments ppaExclude inner join PermissionAccessList paExclude on ppaExclude.paID = paExclude.paID where ppaExclude.cID = {$cInheritPermissionsFromCID} and accessType = " . PermissionKey::ACCESS_TYPE_EXCLUDE . " and pdID in (" . implode(',', $activePDIDs) . ")
  148. and paExclude.peID in (" . implode(',', $peIDs) . ") and (if(paExclude.peID = " . $owpae->getAccessEntityID() . " and p1.uID <>" . $uID . ", false, true)) and (ppaExclude.pkID = " . $vpPKID . $cvIsApproved . ")) = 0)");
  149. }
  150. public function sortByRelevance() {
  151. if ($this->indexedSearch) {
  152. parent::sortBy('cIndexScore', 'desc');
  153. }
  154. }
  155. /**
  156. * Sorts this list by display order
  157. */
  158. public function sortByDisplayOrder() {
  159. parent::sortBy('p1.cDisplayOrder', 'asc');
  160. }
  161. /**
  162. * Sorts this list by display order descending
  163. */
  164. public function sortByDisplayOrderDescending() {
  165. parent::sortBy('p1.cDisplayOrder', 'desc');
  166. }
  167. public function sortByCollectionIDAscending() {
  168. parent::sortBy('p1.cID', 'asc');
  169. }
  170. /**
  171. * Sorts this list by public date ascending order
  172. */
  173. public function sortByPublicDate() {
  174. parent::sortBy('cvDatePublic', 'asc');
  175. }
  176. /**
  177. * Sorts this list by name
  178. */
  179. public function sortByName() {
  180. parent::sortBy('cvName', 'asc');
  181. }
  182. /**
  183. * Sorts this list by name descending order
  184. */
  185. public function sortByNameDescending() {
  186. parent::sortBy('cvName', 'desc');
  187. }
  188. /**
  189. * Sorts this list by public date descending order
  190. */
  191. public function sortByPublicDateDescending() {
  192. parent::sortBy('cvDatePublic', 'desc');
  193. }
  194. /**
  195. * Sets the parent ID that we will grab pages from.
  196. * @param mixed $cParentID
  197. */
  198. public function filterByParentID($cParentID) {
  199. $db = Loader::db();
  200. if (is_array($cParentID)) {
  201. $cth = '(';
  202. for ($i = 0; $i < count($cParentID); $i++) {
  203. if ($i > 0) {
  204. $cth .= ',';
  205. }
  206. $cth .= $db->quote($cParentID[$i]);
  207. }
  208. $cth .= ')';
  209. $this->filter(false, "(p1.cParentID in {$cth})");
  210. } else {
  211. $this->filterByCParentID = $cParentID;
  212. $this->filter('p1.cParentID', $cParentID);
  213. }
  214. }
  215. /**
  216. * Filters by type of collection (using the ID field)
  217. * @param mixed $ctID
  218. */
  219. public function filterByCollectionTypeID($ctID) {
  220. $this->filterByCT = true;
  221. $this->filter("pt.ctID", $ctID);
  222. }
  223. /**
  224. * Filters by user ID of collection (using the uID field)
  225. * @param mixed $ctID
  226. */
  227. public function filterByUserID($uID) {
  228. if ($this->includeAliases) {
  229. $this->filter(false, "(p1.uID = $uID or p2.uID = $uID)");
  230. } else {
  231. $this->filter('p1.uID', $uID);
  232. }
  233. }
  234. public function filterByIsApproved($cvIsApproved) {
  235. $this->filter('cv.cvIsApproved', $cvIsApproved);
  236. }
  237. public function filterByIsAlias($ia) {
  238. if ($this->includeAliases) {
  239. if ($ia == true) {
  240. $this->filter(false, "(p2.cPointerID is not null)");
  241. } else {
  242. $this->filter(false, "(p2.cPointerID is null)");
  243. }
  244. }
  245. }
  246. /**
  247. * Filters by type of collection (using the handle field)
  248. * @param mixed $ctID
  249. */
  250. public function filterByCollectionTypeHandle($ctHandle) {
  251. $db = Loader::db();
  252. $this->filterByCT = true;
  253. if (is_array($ctHandle)) {
  254. $cth = '(';
  255. for ($i = 0; $i < count($ctHandle); $i++) {
  256. if ($i > 0) {
  257. $cth .= ',';
  258. }
  259. $cth .= $db->quote($ctHandle[$i]);
  260. }
  261. $cth .= ')';
  262. $this->filter(false, "(pt.ctHandle in {$cth})");
  263. } else {
  264. $this->filter('pt.ctHandle', $ctHandle);
  265. }
  266. }
  267. /**
  268. * Filters by date added
  269. * @param string $date
  270. */
  271. public function filterByDateAdded($date, $comparison = '=') {
  272. $this->filter('c.cDateAdded', $date, $comparison);
  273. }
  274. public function filterByNumberOfChildren($num, $comparison = '>') {
  275. if (!Loader::helper('validation/numbers')->integer($num)) {
  276. $num = 0;
  277. }
  278. if ($this->includeAliases) {
  279. $this->filter(false, '(p1.cChildren ' . $comparison . ' ' . $num . ' or p2.cChildren ' . $comparison . ' ' . $num . ')');
  280. } else {
  281. $this->filter('p1.cChildren', $num, $comparison);
  282. }
  283. }
  284. public function filterByDateLastModified($date, $comparison = '=') {
  285. $this->filter('c.cDateModified', $date, $comparison);
  286. }
  287. /**
  288. * Filters by public date
  289. * @param string $date
  290. */
  291. public function filterByPublicDate($date, $comparison = '=') {
  292. $this->filter('cv.cvDatePublic', $date, $comparison);
  293. }
  294. /***
  295. * Like filterByAttribute(), but wraps values properly for "select" type attributes.
  296. * Accepts either a single value, or an array of values.
  297. * If an array of values is provided, they will be combined together with "OR".
  298. * (If you need to do an "AND" filter on mulitple values, just call this function multiple times).
  299. */
  300. public function filterBySelectAttribute($akHandle, $value) {
  301. if (empty($value)) {
  302. return;
  303. }
  304. //Determine if this attribute allows multiple selections
  305. $ak = CollectionAttributeKey::getByHandle($akHandle);
  306. $akc = $ak->getController();
  307. $isMultiSelect = $akc->getAllowMultipleValues();
  308. //Explanation of query logic: "select" attributes wrap each value in newline characters when
  309. // saving to the db, which allows parsing of individual values within a "multi-select" attribute.
  310. //
  311. //Because of this, you need to query them using the "LIKE" operator and the "%" wildcards
  312. // when the attribute is "multi-select" (although for "single-select" attributes
  313. // you can speed things up by just using "=" and excluding the "%" wildcards).
  314. //
  315. //Things get trickier if you want to string together several values with an "OR"
  316. // (for example, "find all pages whose 'tags' attribute is 'hello' OR 'world'")
  317. // -- the usual "filterBy" methods don't work because they always use "AND" to combine
  318. // multiple criteria. So instead we can manually create our own portion of the "WHERE"
  319. // clause and pass that directly to the raw "filter" attribute.
  320. if (is_array($value)) {
  321. $db = Loader::db();
  322. $criteria = array();
  323. foreach ($value as $v) {
  324. $escapedValue = $db->escape($v);
  325. if ($isMultiSelect) {
  326. $criteria[] = "(ak_{$akHandle} LIKE '%\n{$escapedValue}\n%')";
  327. } else {
  328. $criteria[] = "(ak_{$akHandle} = '\n{$escapedValue}\n')";
  329. }
  330. }
  331. $where = '(' . implode(' OR ', $criteria) . ')';
  332. $this->filter(false, $where);
  333. } else if ($isMultiSelect) {
  334. $this->filterByAttribute($akHandle, "%\n{$value}\n%", 'LIKE');
  335. } else {
  336. $this->filterByAttribute($akHandle, "\n{$value}\n");
  337. }
  338. }
  339. /**
  340. * If true, pages will be checked for permissions prior to being returned
  341. * @param bool $checkForPermissions
  342. */
  343. public function displayOnlyPermittedPages($checkForPermissions) {
  344. if ($checkForPermissions) {
  345. $this->ignorePermissions = false;
  346. } else {
  347. $this->ignorePermissions = true;
  348. }
  349. }
  350. protected function setBaseQuery($additionalFields = '') {
  351. if ($this->isIndexedSearch()) {
  352. $db = Loader::db();
  353. $ik = ', match(psi.cName, psi.cDescription, psi.content) against (' . $db->quote($this->indexedKeywords) . ') as cIndexScore ';
  354. }
  355. if (!$this->includeAliases) {
  356. $this->filter(false, '(p1.cPointerID < 1 or p1.cPointerID is null)');
  357. }
  358. $cvID = '(select max(cvID) from CollectionVersions where cID = cv.cID)';
  359. if ($this->displayOnlyApprovedPages) {
  360. $cvID = '(select cvID from CollectionVersions where cvIsApproved = 1 and cID = cv.cID)';
  361. $this->filter('cvIsApproved', 1);
  362. }
  363. if ($this->includeAliases) {
  364. $this->setQuery('select p1.cID, pt.ctHandle ' . $ik . $additionalFields . ' from Pages p1 left join Pages p2 on (p1.cPointerID = p2.cID) left join PagePaths on (PagePaths.cID = p1.cID and PagePaths.ppIsCanonical = 1) left join PageSearchIndex psi on (psi.cID = if(p2.cID is null, p1.cID, p2.cID)) inner join CollectionVersions cv on (cv.cID = if(p2.cID is null, p1.cID, p2.cID) and cvID = ' . $cvID . ') left join PageTypes pt on pt.ctID = cv.ctID inner join Collections c on (c.cID = if(p2.cID is null, p1.cID, p2.cID))');
  365. } else {
  366. $this->setQuery('select p1.cID, pt.ctHandle ' . $ik . $additionalFields . ' from Pages p1 left join PagePaths on (PagePaths.cID = p1.cID and PagePaths.ppIsCanonical = 1) left join PageSearchIndex psi on (psi.cID = p1.cID) inner join CollectionVersions cv on (cv.cID = p1.cID and cvID = ' . $cvID . ') left join PageTypes pt on (pt.ctID = cv.ctID) inner join Collections c on (c.cID = p1.cID)');
  367. }
  368. if ($this->includeAliases) {
  369. $this->filter(false, "(p1.cIsTemplate = 0 or p2.cIsTemplate = 0)");
  370. } else {
  371. $this->filter('p1.cIsTemplate', 0);
  372. }
  373. $this->setupPermissions();
  374. if ($this->includeAliases) {
  375. $this->setupAttributeFilters("left join CollectionSearchIndexAttributes on (CollectionSearchIndexAttributes.cID = if (p2.cID is null, p1.cID, p2.cID))");
  376. } else {
  377. $this->setupAttributeFilters("left join CollectionSearchIndexAttributes on (CollectionSearchIndexAttributes.cID = p1.cID)");
  378. }
  379. if ($this->displayOnlyActivePages) {
  380. $this->filter('p1.cIsActive', 1);
  381. }
  382. $this->setupSystemPagesToExclude();
  383. }
  384. protected function setupSystemPagesToExclude() {
  385. if ($this->includeSystemPages || $this->filterByCParentID > 1 || $this->filterByCT == true) {
  386. return false;
  387. }
  388. if ($this->includeAliases) {
  389. $this->filter(false, "(p1.cIsSystemPage = 0 or p2.cIsSystemPage = 0)");
  390. } else {
  391. $this->filter(false, "(p1.cIsSystemPage = 0)");
  392. }
  393. }
  394. protected function loadPageID($cID, $versionOrig = 'RECENT') {
  395. return Page::getByID($cID, $versionOrig);
  396. }
  397. public function getTotal() {
  398. if ($this->getQuery() == '') {
  399. $this->setBaseQuery();
  400. }
  401. return parent::getTotal();
  402. }
  403. /**
  404. * Returns an array of page objects based on current settings
  405. */
  406. public function get($itemsToGet = 0, $offset = 0) {
  407. $pages = array();
  408. if ($this->getQuery() == '') {
  409. $this->setBaseQuery();
  410. }
  411. $this->setItemsPerPage($itemsToGet);
  412. $r = parent::get($itemsToGet, $offset);
  413. foreach($r as $row) {
  414. $nc = $this->loadPageID($row['cID'], 'ACTIVE');
  415. if (!$this->displayOnlyApprovedPages) {
  416. $cp = new Permissions($nc);
  417. if ($cp->canViewPageVersions()) {
  418. $nc->loadVersionObject('RECENT');
  419. }
  420. }
  421. $nc->setPageIndexScore($row['cIndexScore']);
  422. $pages[] = $nc;
  423. }
  424. return $pages;
  425. }
  426. }
  427. class Concrete5_Model_PageSearchDefaultColumnSet extends DatabaseItemListColumnSet {
  428. protected $attributeClass = 'CollectionAttributeKey';
  429. public static function getCollectionDatePublic($c) {
  430. return date(DATE_APP_DASHBOARD_SEARCH_RESULTS_PAGES, strtotime($c->getCollectionDatePublic()));
  431. }
  432. public static function getCollectionDateModified($c) {
  433. return date(DATE_APP_DASHBOARD_SEARCH_RESULTS_PAGES, strtotime($c->getCollectionDateLastModified()));
  434. }
  435. public function getCollectionAuthor($c) {
  436. $uID = $c->getCollectionUserID();
  437. $ui = UserInfo::getByID($uID);
  438. if (is_object($ui)) {
  439. return $ui->getUserName();
  440. }
  441. }
  442. public function __construct() {
  443. $this->addColumn(new DatabaseItemListColumn('ctHandle', t('Type'), 'getCollectionTypeName', false));
  444. $this->addColumn(new DatabaseItemListColumn('cvName', t('Name'), 'getCollectionName'));
  445. $this->addColumn(new DatabaseItemListColumn('cvDatePublic', t('Date'), array('PageSearchDefaultColumnSet', 'getCollectionDatePublic')));
  446. $this->addColumn(new DatabaseItemListColumn('cDateModified', t('Last Modified'), array('PageSearchDefaultColumnSet', 'getCollectionDateModified')));
  447. $this->addColumn(new DatabaseItemListColumn('author', t('Author'), array('PageSearchDefaultColumnSet', 'getCollectionAuthor'), false));
  448. $date = $this->getColumnByKey('cDateModified');
  449. $this->setDefaultSortColumn($date, 'desc');
  450. }
  451. }
  452. class Concrete5_Model_PageSearchAvailableColumnSet extends Concrete5_Model_PageSearchDefaultColumnSet {
  453. protected $attributeClass = 'CollectionAttributeKey';
  454. public function __construct() {
  455. parent::__construct();
  456. }
  457. }
  458. class Concrete5_Model_PageSearchColumnSet extends DatabaseItemListColumnSet {
  459. protected $attributeClass = 'CollectionAttributeKey';
  460. public function getCurrent() {
  461. $u = new User();
  462. $fldc = $u->config('PAGE_LIST_DEFAULT_COLUMNS');
  463. if ($fldc != '') {
  464. $fldc = @unserialize($fldc);
  465. }
  466. if (!($fldc instanceof DatabaseItemListColumnSet)) {
  467. $fldc = new PageSearchDefaultColumnSet();
  468. }
  469. return $fldc;
  470. }
  471. }