PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Ip/Internal/Pages/Model.php

https://gitlab.com/x33n/ImpressPages
PHP | 801 lines | 575 code | 79 blank | 147 comment | 71 complexity | 10b0fa8f5ce70444edbd832d8d54ce6b MD5 | raw file
  1. <?php
  2. /**
  3. * @package ImpressPages
  4. *
  5. */
  6. namespace Ip\Internal\Pages;
  7. class Model
  8. {
  9. /**
  10. * Move page to trash
  11. *
  12. * @param int $pageId
  13. * @param int $deleteType
  14. */
  15. public static function moveToTrash($pageId, $deleteType = 1)
  16. {
  17. $children = self::getChildren($pageId);
  18. if ($children) {
  19. foreach ($children as $child) {
  20. self::moveToTrash($child['id'], 2);
  21. }
  22. }
  23. ipDb()->update(
  24. 'page',
  25. array('isDeleted' => $deleteType, 'deletedAt' => date('Y-m-d H:i:s')),
  26. array('id' => $pageId)
  27. );
  28. ipEvent('ipPageMarkedAsDeleted', array('pageId' => $pageId));
  29. }
  30. /**
  31. * Copy page
  32. *
  33. * @param int $pageId
  34. * @param $destinationPageId
  35. * @param int $position page position in the subtree //TODO implement
  36. * @internal param int $newParentId
  37. * @return int
  38. */
  39. public static function copyPage($pageId, $destinationPageId, $destinationPosition = null)
  40. {
  41. $children = self::getChildren($destinationPageId);
  42. $newPageOrder = 1;
  43. if (count($children) > 0) {
  44. $newPageOrder = $children[0]['pageOrder'] - 1; // Set as first page.
  45. if ($destinationPosition > 0) {
  46. if (isset($children[$destinationPosition - 1]) && isset($children[$destinationPosition])) { // New position is in the middle of other pages.
  47. $newPageOrder = ($children[$destinationPosition - 1]['pageOrder'] + $children[$destinationPosition]['pageOrder']) / 2; // Average
  48. } else { // New position is at the end.
  49. $newPageOrder = $children[count($children) - 1]['pageOrder'] + 1;
  50. }
  51. }
  52. }
  53. return self::_copyPageRecursion($pageId, $destinationPageId, $newPageOrder);
  54. }
  55. /**
  56. * Copy page internal recursion
  57. *
  58. * @param int $nodeId
  59. * @param int $destinationPageId
  60. * @param int $rowNumber
  61. * @param array $newPages
  62. * @return int
  63. */
  64. private static function _copyPageRecursion($nodeId, $destinationPageId, $rowNumber, $newPages = null)
  65. {
  66. // $newPages are the pages that have been copied already and should be skipped to duplicate again. This situation can occur when copying the page to it self.
  67. if ($newPages == null) {
  68. $newPages = array();
  69. }
  70. $newNodeId = static::copySinglePage($nodeId, $destinationPageId, $rowNumber);
  71. $newPages[$newNodeId] = 1;
  72. self::_copyWidgets($nodeId, $newNodeId);
  73. $children = self::getChildren($nodeId);
  74. if ($children) {
  75. foreach ($children as $key => $lock) {
  76. if (!isset($newPages[$lock['id']])) {
  77. self::_copyPageRecursion($lock['id'], $newNodeId, $key, $newPages);
  78. }
  79. }
  80. }
  81. return $newNodeId;
  82. }
  83. /**
  84. * Copy single page
  85. *
  86. * @param int $nodeId
  87. * @param int $newParentId
  88. * @param int $newIndex
  89. * @return bool|string
  90. */
  91. public static function copySinglePage($nodeId, $newParentId, $newIndex)
  92. {
  93. $copy = ipDb()->selectRow('page', '*', array('id' => $nodeId));
  94. if (!$copy) {
  95. trigger_error('Element does not exist');
  96. }
  97. $menu = ipContent()->getPageMenu($newParentId);
  98. if ($menu) {
  99. $copy['languageCode'] = $menu->getLanguageCode();
  100. }
  101. unset($copy['id']);
  102. $copy['parentId'] = $newParentId;
  103. $copy['pageOrder'] = $newIndex;
  104. $copy['urlPath'] = UrlAllocator::allocatePath($copy['languageCode'], $copy['urlPath']);
  105. $copy['createdAt'] = date('Y-m-d H:i:s');
  106. $copy['updatedAt'] = date('Y-m-d H:i:s');
  107. $pageId = ipDb()->insert('page', $copy);
  108. $eventInfo = ipDb()->selectRow('page', '*', array('id' => $pageId));
  109. $eventInfo['sourceId'] = $nodeId;
  110. ipEvent('ipPageDuplicated', $eventInfo);
  111. return $pageId;
  112. }
  113. /**
  114. * @param int $sourceId
  115. * @param int $targetId
  116. */
  117. private static function _copyWidgets($sourceId, $targetId)
  118. {
  119. $oldRevision = \Ip\Internal\Revision::getPublishedRevision($sourceId);
  120. \Ip\Internal\Revision::duplicateRevision($oldRevision['revisionId'], $targetId, 1);
  121. }
  122. /**
  123. * Get properties of menu
  124. *
  125. * @param string $languageCode
  126. * @param string $alias
  127. * @return array|null
  128. */
  129. public static function getMenu($languageCode, $alias)
  130. {
  131. return ipDb()->selectRow(
  132. 'page',
  133. '*',
  134. array('languageCode' => $languageCode, 'alias' => $alias, 'isDeleted' => 0)
  135. );
  136. }
  137. /**
  138. * Get children
  139. *
  140. * @param int $parentId
  141. * @param int $start
  142. * @param int $limit
  143. * @return array
  144. */
  145. public static function getChildren($parentId, $start = null, $limit = null)
  146. {
  147. $sqlEnd = 'ORDER BY `pageOrder`';
  148. if ($start !== null || $limit !== null) {
  149. $sqlEnd .= ' LIMIT ' . (int)$start;
  150. }
  151. if ($limit !== null) {
  152. $sqlEnd .= ', ' . (int)$limit;
  153. }
  154. return ipDb()->selectAll('page', '*', array('parentId' => $parentId, 'isDeleted' => 0), $sqlEnd);
  155. }
  156. public static function getDefaultMenuPagePosition($menuAlias, $whenPageIsSelected, $default)
  157. {
  158. $key = 'menu_' . $menuAlias . '_default_position';
  159. if ($whenPageIsSelected) {
  160. $key .= '_selected';
  161. }
  162. return ipStorage()->get('Pages', $key, $default);
  163. }
  164. public static function setDefaultMenuPagePosition($menuAlias, $whenPageIsSelected, $position)
  165. {
  166. $key = 'menu_' . $menuAlias . '_default_position';
  167. if ($whenPageIsSelected) {
  168. $key .= '_selected';
  169. }
  170. ipStorage()->set('Pages', $key, $position);
  171. }
  172. /**
  173. * Get menu list
  174. *
  175. * @param string $languageCode
  176. * @return array
  177. */
  178. public static function getMenuList($languageCode = null)
  179. {
  180. $where = array('parentId' => 0, 'isDeleted' => 0);
  181. if ($languageCode !== null) {
  182. $where['languageCode'] = $languageCode;
  183. }
  184. $list = ipDb()->selectAll('page', '*', $where, ' ORDER BY `pageOrder` ');
  185. return $list;
  186. }
  187. /**
  188. * Get page
  189. *
  190. * @param int $pageId
  191. * @return array|null
  192. */
  193. public static function getPage($pageId)
  194. {
  195. return ipDb()->selectRow('page', '*', array('id' => $pageId, 'isDeleted' => 0));
  196. }
  197. /**
  198. * Get pages by URL
  199. *
  200. * @param string $languageCode
  201. * @param string $urlPath
  202. * @return array|null
  203. */
  204. public static function getPageByUrl($languageCode, $urlPath)
  205. {
  206. $page = ipDb()->selectRow(
  207. 'page',
  208. '*',
  209. array('languageCode' => $languageCode, 'urlPath' => $urlPath, 'isDeleted' => 0)
  210. );
  211. if ($page) {
  212. return $page;
  213. }
  214. //if lash exists, remove. If there is no slash, add it.
  215. if (substr($urlPath, -1) == '/') {
  216. $urlPath = substr($urlPath, 0, -1);
  217. } else {
  218. $urlPath .= '/';
  219. }
  220. $page = ipDb()->selectRow(
  221. 'page',
  222. '*',
  223. array('languageCode' => $languageCode, 'urlPath' => $urlPath, 'isDeleted' => 0)
  224. );
  225. return $page;
  226. }
  227. /**
  228. * Get pages by alias
  229. *
  230. * @param string $languageCode
  231. * @param string $alias
  232. * @return array|null
  233. */
  234. public static function getPageByAlias($languageCode, $alias)
  235. {
  236. return ipDb()->selectRow(
  237. 'page',
  238. '*',
  239. array('languageCode' => $languageCode, 'alias' => $alias, 'isDeleted' => 0)
  240. );
  241. }
  242. /**
  243. * Get next page order
  244. *
  245. * @param array $where
  246. * @return int
  247. */
  248. protected static function getNextPageOrder($where)
  249. {
  250. if (empty($where['isDeleted'])) {
  251. $where['isDeleted'] = 0;
  252. }
  253. $nextPageOrder = ipDb()->selectValue('page', 'MAX(`pageOrder`) + 1', $where);
  254. return $nextPageOrder ? $nextPageOrder : 1;
  255. }
  256. /**
  257. * Change URL path of page
  258. *
  259. * @param string $pageId
  260. * @param string $newUrlPath
  261. * @return bool|null
  262. */
  263. protected static function changePageUrlPath($pageId, $newUrlPath)
  264. {
  265. $pageBeforeChange = ipPage($pageId);
  266. if (ipGetOption('Config.trailingSlash', 1)) {
  267. if (mb_substr($newUrlPath, -1) != '/') {
  268. $newUrlPath .= '/';
  269. }
  270. } else {
  271. if (mb_substr($newUrlPath, -1) == '/') {
  272. $newUrlPath = mb_substr($newUrlPath, 0, -1);
  273. }
  274. }
  275. if ($newUrlPath == $pageBeforeChange->getUrlPath()) {
  276. return false;
  277. }
  278. $allocatedPath = UrlAllocator::allocatePath($pageBeforeChange->getLanguageCode(), $newUrlPath);
  279. ipDb()->update('page', array('urlPath' => $allocatedPath), array('id' => $pageId));
  280. $pageAfterChange = ipPage($pageId);
  281. $oldUrl = $pageBeforeChange->getLink();
  282. if (substr($oldUrl, -1) == '/') {
  283. $oldUrl = substr($oldUrl, 0, -1);
  284. }
  285. $newUrl = $pageAfterChange->getLink();
  286. if (substr($newUrl, -1) == '/') {
  287. $newUrl = substr($newUrl, 0, -1);
  288. }
  289. ipEvent(
  290. 'ipUrlChanged',
  291. array(
  292. 'oldUrl' => $oldUrl,
  293. 'newUrl' => $newUrl,
  294. )
  295. );
  296. return null;
  297. }
  298. /**
  299. * Update properties of page
  300. *
  301. * @param int $pageId
  302. * @param array $properties
  303. * @return bool
  304. */
  305. public static function updatePageProperties($pageId, $properties)
  306. {
  307. $update = array();
  308. if (isset($properties['title'])) {
  309. $update['title'] = $properties['title'];
  310. }
  311. if (isset($properties['metaTitle'])) {
  312. $update['metaTitle'] = $properties['metaTitle'];
  313. }
  314. if (isset($properties['keywords'])) {
  315. $update['keywords'] = $properties['keywords'];
  316. }
  317. if (isset($properties['description'])) {
  318. $update['description'] = $properties['description'];
  319. }
  320. if (isset($properties['createdAt']) && strtotime($properties['createdAt']) !== false) {
  321. $update['createdAt'] = $properties['createdAt'];
  322. }
  323. if (isset($properties['updatedAt']) && strtotime($properties['updatedAt']) !== false) {
  324. $update['updatedAt'] = $properties['updatedAt'];
  325. }
  326. if (isset($properties['type'])) {
  327. $update['type'] = $properties['type'];
  328. }
  329. if (isset($properties['redirectUrl'])) {
  330. $update['redirectUrl'] = $properties['redirectUrl'];
  331. }
  332. if (isset($properties['isDisabled'])) {
  333. $update['isDisabled'] = $properties['isDisabled'];
  334. }
  335. if (isset($properties['isSecured'])) {
  336. $update['isSecured'] = $properties['isSecured'];
  337. }
  338. if (isset($properties['isVisible'])) {
  339. $update['isVisible'] = $properties['isVisible'];
  340. }
  341. if (isset($properties['alias'])) {
  342. $update['alias'] = $properties['alias'];
  343. }
  344. if (isset($properties['isBlank'])) {
  345. $update['isBlank'] = $properties['isBlank'];
  346. }
  347. if (!empty($properties['layout'])) {
  348. $update['layout'] = $properties['layout'];
  349. $menu = ipContent()->getPageMenu($pageId);
  350. if ($menu && $menu->getLayout() == $properties['layout']) {
  351. $update['layout'] = null;
  352. }
  353. }
  354. if (count($update) != 0) {
  355. ipDb()->update('page', $update, array('id' => $pageId));
  356. }
  357. if (!empty($properties['type'])) {
  358. $update['type'] = $properties['type'];
  359. }
  360. if (isset($properties['urlPath'])) {
  361. self::changePageUrlPath($pageId, $properties['urlPath']);
  362. }
  363. $properties['id'] = $pageId;
  364. ipEvent('ipPageUpdated', $properties);
  365. return true;
  366. }
  367. /**
  368. * Is child page?
  369. *
  370. * @param int $pageId
  371. * @param int $parentId
  372. * @return bool
  373. */
  374. public static function isChild($pageId, $parentId)
  375. {
  376. $page = self::getPage($pageId);
  377. if (!$page) {
  378. return false;
  379. }
  380. if ($page['parentId'] == $parentId) {
  381. return true;
  382. }
  383. if ($page['parentId']) {
  384. return self::isChild($page['parentId'], $parentId);
  385. }
  386. return false;
  387. }
  388. /**
  389. * Move page
  390. *
  391. * @param $pageId
  392. * @param int $destinationParentId
  393. * @param int $destinationPosition
  394. * @throws \Ip\Exception
  395. * @internal param int $menuId
  396. */
  397. public static function movePage($pageId, $destinationParentId, $destinationPosition)
  398. {
  399. if ((int)$pageId === (int)$destinationParentId || static::isChild($destinationParentId, $pageId)) {
  400. throw new \Ip\Exception("Can't move page inside itself.");
  401. }
  402. $parent = ipContent()->getPage($destinationParentId);
  403. $newParentChildren = self::getChildren($destinationParentId);
  404. $newPageOrder = 0; // Initial value.
  405. if (count($newParentChildren) > 0) {
  406. $newPageOrder = $newParentChildren[0]['pageOrder'] - 1; // Set as first page.
  407. if ($destinationPosition > 0) {
  408. if (isset($newParentChildren[$destinationPosition - 1]) && isset($newParentChildren[$destinationPosition])) { // New position is in the middle of other pages.
  409. $newPageOrder = ($newParentChildren[$destinationPosition - 1]['pageOrder'] + $newParentChildren[$destinationPosition]['pageOrder']) / 2; // Average
  410. } else { // New position is at the end.
  411. $newPageOrder = $newParentChildren[count($newParentChildren) - 1]['pageOrder'] + 1;
  412. }
  413. }
  414. }
  415. $update = array(
  416. 'parentId' => $destinationParentId,
  417. 'pageOrder' => $newPageOrder,
  418. 'languageCode' => $parent->getLanguageCode()
  419. );
  420. $eventData = array(
  421. 'pageId' => $pageId,
  422. 'destinationParentId' => $destinationParentId,
  423. 'destinationPosition' => $destinationPosition
  424. );
  425. ipEvent('ipBeforePageMoved', $eventData);
  426. ipDb()->update('page', $update, array('id' => $pageId));
  427. $children = self::getChildren($pageId);
  428. if ($children) {
  429. foreach ($children as $child) {
  430. ipDb()->update('page', array('languageCode' => $update['languageCode']), array('id' => $child['id']));
  431. }
  432. }
  433. ipEvent('ipPageMoved', $eventData);
  434. }
  435. /**
  436. * Update properties of menu
  437. *
  438. * @param int $menuId
  439. * @param string $alias
  440. * @param string $title
  441. * @param string $layout
  442. * @param string $type
  443. */
  444. public static function updateMenu($menuId, $alias, $title, $layout, $type)
  445. {
  446. $properties = array(
  447. 'alias' => $alias,
  448. 'title' => $title,
  449. 'layout' => $layout,
  450. 'type' => $type
  451. );
  452. self::updatePageProperties($menuId, $properties);
  453. }
  454. /**
  455. * @param $languageCode
  456. * @param $alias
  457. * @param $title
  458. * @param string $type
  459. * @return int
  460. */
  461. public static function createMenu($languageCode, $alias, $title, $type = 'tree')
  462. {
  463. $data = array();
  464. $data['languageCode'] = $languageCode;
  465. if (empty($alias)) {
  466. $alias = \Ip\Internal\Text\Specialchars::url($title);
  467. }
  468. $data['alias'] = static::allocateUniqueAlias($languageCode, $alias);
  469. $data['title'] = $title;
  470. $data['type'] = $type;
  471. $data['parentId'] = 0;
  472. $data['pageOrder'] = static::getNextPageOrder(
  473. array('languageCode' => $languageCode, 'parentId' => $data['parentId'])
  474. );
  475. $data['isVisible'] = 1;
  476. return self::addPage(0, $data);
  477. }
  478. /**
  479. * Allocate unique alias
  480. *
  481. * @param string $languageCode
  482. * @param string $alias
  483. * @return string
  484. */
  485. protected static function allocateUniqueAlias($languageCode, $alias)
  486. {
  487. $condition = array('languageCode' => $languageCode, 'alias' => $alias, 'isDeleted' => 0);
  488. $exists = ipDb()->selectValue('page', 'id', $condition);
  489. if (!$exists) {
  490. return $alias;
  491. }
  492. $i = 2;
  493. while (ipDb()->selectValue(
  494. 'page',
  495. 'id',
  496. array('languageCode' => $languageCode, 'alias' => $alias . '-' . $i, 'isDeleted' => 0)
  497. )) {
  498. $i++;
  499. }
  500. return $alias . '-' . $i;
  501. }
  502. /**
  503. * Insert new page
  504. *
  505. * @param int $parentId
  506. * @param array $params
  507. * @return int
  508. */
  509. public static function addPage($parentId, $params)
  510. {
  511. $pageOrderCondition = array(
  512. 'parentId' => $parentId,
  513. );
  514. if (!empty($params['languageCode'])) {
  515. $pageOrderCondition['languageCode'] = $params['languageCode'];
  516. }
  517. $row = array(
  518. 'parentId' => $parentId,
  519. 'pageOrder' => self::getNextPageOrder($pageOrderCondition),
  520. );
  521. $fields = array(
  522. 'title',
  523. 'metaTitle',
  524. 'languageCode',
  525. 'keywords',
  526. 'description',
  527. 'urlPath',
  528. 'createdAt',
  529. 'updatedAt',
  530. 'type',
  531. 'isVisible',
  532. 'alias'
  533. );
  534. foreach ($fields as $column) {
  535. if (array_key_exists($column, $params)) {
  536. $row[$column] = $params[$column];
  537. }
  538. }
  539. if (!empty($row['urlPath']) && ipGetOption('Config.trailingSlash', 1) && substr($row['urlPath'], -1) != '/') {
  540. $row['urlPath'] .= '/';
  541. }
  542. if (empty($row['createdAt'])) {
  543. $row['createdAt'] = date('Y-m-d H:i:s');
  544. }
  545. if (empty($row['updatedAt'])) {
  546. $row['updatedAt'] = date('Y-m-d H:i:s');
  547. }
  548. $pageId = ipDb()->insert('page', $row);
  549. $row['id'] = $pageId;
  550. ipEvent('ipPageAdded', $row);
  551. return $pageId;
  552. }
  553. /**
  554. * Change menu order
  555. *
  556. * @param int $menuId
  557. * @param int $newIndex
  558. */
  559. public static function changeMenuOrder($menuId, $newIndex)
  560. {
  561. $menu = static::getPage($menuId);
  562. $menus = static::getMenuList($menu['languageCode']);
  563. $newPriority = null;
  564. if ($newIndex <= 0) {
  565. $newPriority = $menus[0]['pageOrder'] - 20;
  566. } elseif ($newIndex > count($menus) - 1) {
  567. $lastMenu = end($menus);
  568. $newPriority = $lastMenu['pageOrder'] + 20;
  569. } else {
  570. $newPriority = ($menus[$newIndex - 1]['pageOrder'] + $menus[$newIndex]['pageOrder']) / 2;
  571. }
  572. ipDb()->update('page', array('pageOrder' => $newPriority), array('id' => $menuId));
  573. }
  574. /**
  575. * Update URL
  576. *
  577. * @param string $oldUrl
  578. * @param string $newUrl
  579. */
  580. public static function updateUrl($oldUrl, $newUrl)
  581. {
  582. $old = parse_url($oldUrl);
  583. $new = parse_url($newUrl);
  584. $oldPart = $old['host'] . rtrim($old['path'], '/');
  585. $newPart = $new['host'] . rtrim($new['path'], '/');
  586. $replaces = array(
  587. 'http://' . $oldPart => 'http://' . $newPart,
  588. 'http://' . $oldPart . '/' => 'http://' . $newPart . '/',
  589. 'https://' . $oldPart => 'https://' . $newPart,
  590. 'https://' . $oldPart . '/' => 'https://' . $newPart . '/',
  591. );
  592. if ($newUrl == ipConfig()->baseUrl()) {
  593. //the whole website URL has changed
  594. $table = ipTable('page');
  595. $sql = "
  596. UPDATE
  597. $table
  598. SET
  599. `redirectUrl` = REPLACE(`redirectUrl`, :search, :replace)
  600. WHERE
  601. 1
  602. ";
  603. foreach ($replaces as $search => $replace) {
  604. ipDb()->execute($sql, array('search' => $search, 'replace' => $replace));
  605. }
  606. } else {
  607. //single page URL has changed
  608. foreach ($replaces as $search => $replace) {
  609. ipDb()->update('page', array('redirectUrl' => $replace), array('redirectUrl' => $search));
  610. }
  611. }
  612. }
  613. /**
  614. * Removes deleted page and its children from the trash.
  615. *
  616. * Does not remove page if page is not deleted.
  617. * @param int $pageId
  618. * @return int Number of pages deleted.
  619. */
  620. public static function removeDeletedPage($pageId)
  621. {
  622. $canBeDeleted = ipDb()->selectValue('page', 'id', array('id' => $pageId, 'isDeleted' => 1));
  623. if (!$canBeDeleted) {
  624. return false;
  625. }
  626. return static::_removeDeletedPage($pageId);
  627. }
  628. /**
  629. * We assume page is safe to delete.
  630. *
  631. * @param int $pageId
  632. * @return int Count of deleted pages.
  633. */
  634. protected static function _removeDeletedPage($pageId)
  635. {
  636. $deletedPageCount = 0;
  637. $children = ipDb()->selectAll('page', array('id', 'isDeleted'), array('parentId' => $pageId));
  638. foreach ($children as $child) {
  639. if ($child['isDeleted']) {
  640. $deletedPageCount += static::_removeDeletedPage($child['id']);
  641. } else {
  642. // This should never happen!
  643. ipLog()->error(
  644. 'Page.pageHasDeletedParent: page {pageId}, parent set to null',
  645. array('pageId' => $child['id'])
  646. );
  647. ipDb()->update('page', array('parentId' => null), array('id' => $child['id']));
  648. }
  649. }
  650. ipEvent('ipBeforePageRemoved', array('pageId' => $pageId));
  651. $count = ipDb()->delete('page', array('id' => $pageId));
  652. ipPageStorage($pageId)->removeAll();
  653. ipEvent('ipPageRemoved', array('pageId' => $pageId));
  654. $deletedPageCount += (int)$count;
  655. return $deletedPageCount;
  656. }
  657. /**
  658. * Recorvery deleted page and its children from the trash.
  659. *
  660. * Does not recovery page if page is not deleted.
  661. * @param int $pageId
  662. * @return int Number of pages recorvered.
  663. */
  664. public static function recoveryDeletedPage($pageId)
  665. {
  666. $canBeRecovery = ipDb()->selectValue('page', 'id', array('id' => $pageId, 'isDeleted' => 1));
  667. if (!$canBeRecovery) {
  668. return false;
  669. }
  670. ipDb()->update('page', array('isDeleted' => 0), array('id' => $pageId));
  671. return 1;
  672. }
  673. /**
  674. * Trash size
  675. *
  676. * @return int Number of trash pages.
  677. */
  678. public static function trashSize()
  679. {
  680. $table = ipTable('page');
  681. $sql = "SELECT COUNT(*)
  682. FROM $table
  683. WHERE `isDeleted` > 0";
  684. return ipDb()->fetchValue($sql);
  685. }
  686. }