2022-03-08 15:55:41 +01:00
<?php namespace ProcessWire;
/**
* ProcessWire Page Paths
*
* Keeps a cache of page paths to improve performance and
* make paths more queryable by selectors.
*
2022-11-05 18:32:48 +01:00
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer
2022-03-08 15:55:41 +01:00
* https://processwire.com
*
2022-11-05 18:32:48 +01:00
* @property array $rootSegments
2022-03-08 15:55:41 +01:00
*
*/
2022-11-05 18:32:48 +01:00
class PagePaths extends WireData implements Module, ConfigurableModule {
2022-03-08 15:55:41 +01:00
public static function getModuleInfo() {
return array(
'title' => 'Page Paths',
2022-11-05 18:32:48 +01:00
'version' => 4,
'summary' => "Enables page paths/urls to be queryable by selectors. Also offers potential for improved load performance. Builds an index at install (may take time on a large site).",
2022-03-08 15:55:41 +01:00
'singular' => true,
'autoload' => true,
2022-11-05 18:32:48 +01:00
);
2022-03-08 15:55:41 +01:00
}
/**
* Table created by this module
*
*/
const dbTableName = 'pages_paths';
/**
* @var Languages|false
*
*/
protected $languages = null;
/**
2022-11-05 18:32:48 +01:00
* Construct
*
2022-03-08 15:55:41 +01:00
*/
2022-11-05 18:32:48 +01:00
public function __construct() {
$this->set('rootSegments', array());
parent::__construct();
2022-03-08 15:55:41 +01:00
}
/**
2022-11-05 18:32:48 +01:00
* Initialize the hooks
2022-03-08 15:55:41 +01:00
*
*/
2022-11-05 18:32:48 +01:00
public function init() {
$pages = $this->wire()->pages;
$pages->addHook('moved', $this, 'hookPageMoved');
$pages->addHook('renamed', $this, 'hookPageMoved');
$pages->addHook('added', $this, 'hookPageMoved');
$pages->addHook('deleted', $this, 'hookPageDeleted');
2022-03-08 15:55:41 +01:00
}
/**
2022-11-05 18:32:48 +01:00
* API ready
2022-03-08 15:55:41 +01:00
*
*/
2022-11-05 18:32:48 +01:00
public function ready() {
if($this->wire()->languages) {
$this->addHookBefore('LanguageSupportFields::languageDeleted', $this, 'hookLanguageDeleted');
2022-03-08 15:55:41 +01:00
}
}
2022-11-05 18:32:48 +01:00
/*** HOOKS ******************************************************************************************/
2022-03-08 15:55:41 +01:00
/**
* Hook called when a page is moved or renamed
*
* @param HookEvent $event
*
*/
public function hookPageMoved(HookEvent $event) {
$page = $event->arguments[0];
2022-11-05 18:32:48 +01:00
// $this->updatePagePath($page->id, $page->path);
$this->updatePagePaths($page);
2022-03-08 15:55:41 +01:00
}
/**
2022-11-05 18:32:48 +01:00
* Hook called when a page is deleted
2022-03-08 15:55:41 +01:00
*
* @param HookEvent $event
*
*/
public function hookPageDeleted(HookEvent $event) {
2022-11-05 18:32:48 +01:00
$table = self::dbTableName;
2022-03-08 15:55:41 +01:00
$page = $event->arguments[0];
2022-11-05 18:32:48 +01:00
$database = $this->wire()->database;
$query = $database->prepare("DELETE FROM $table WHERE pages_id=:pages_id");
2022-03-08 15:55:41 +01:00
$query->bindValue(":pages_id", $page->id, \PDO::PARAM_INT);
$query->execute();
2022-11-05 18:32:48 +01:00
$this->rebuildRootSegments();
2022-03-08 15:55:41 +01:00
}
2022-11-05 18:32:48 +01:00
/**
* When a language is deleted
*
* @param HookEvent $event
*
*/
public function hookLanguageDeleted(HookEvent $event) {
$languages = $this->getLanguages();
if(!$languages) return;
$language = $event->arguments[0]; /** @var Language $language */
if(!$language->id || $language->isDefault()) return;
$table = self::dbTableName;
$database = $this->wire()->database;
$sql = "DELETE FROM $table WHERE language_id=:language_id";
$query = $database->prepare($sql);
$query->bindValue(':language_id', $language->id, \PDO::PARAM_INT);
$this->executeQuery($query);
}
/*** PUBLIC API *************************************************************************************/
2022-03-08 15:55:41 +01:00
/**
* Given a page ID, return the page path, NULL if not found, or boolean false if cannot be determined.
*
2022-11-05 18:32:48 +01:00
* @param int $pageId Page ID
* @param int $languageId Optionally specify language ID for path or 0 for default language
* @return string|null Returns path or null if not found
2022-03-08 15:55:41 +01:00
*
*/
2022-11-05 18:32:48 +01:00
public function getPath($pageId, $languageId = 0) {
2022-03-08 15:55:41 +01:00
$table = self::dbTableName;
2022-11-05 18:32:48 +01:00
$database = $this->wire()->database;
$sanitizer = $this->wire()->sanitizer;
$languageId = $this->languageId($languageId);
$sql = "SELECT path FROM `$table` WHERE pages_id=:pages_id AND language_id=:language_id";
$query = $database->prepare($sql);
$query->bindValue(":pages_id", $pageId, \PDO::PARAM_INT);
$query->bindValue(":language_id", $languageId, \PDO::PARAM_INT);
$path = null;
if(!$this->executeQuery($query)) return $path;
if($query->rowCount()) {
$path = $query->fetchColumn();
$path = strlen($path) ? $sanitizer->pagePathName("/$path/", Sanitizer::toUTF8) : '/';
}
$query->closeCursor();
2022-03-08 15:55:41 +01:00
return $path;
}
2022-11-05 18:32:48 +01:00
/**
* Given a page ID, return all paths found for page
*
* Return value is indexed by language ID (and index 0 for default language)
*
* @param int $pageId Page ID
* @return array
*
*/
public function getPaths($pageId) {
$table = self::dbTableName;
$database = $this->wire()->database;
$sanitizer = $this->wire()->sanitizer;
$paths = array();
$sql = "SELECT path, language_id FROM `$table` WHERE pages_id=:pages_id ";
$query = $database->prepare($sql);
$query->bindValue(":pages_id", $pageId, \PDO::PARAM_INT);
if(!$this->executeQuery($query)) return $paths;
while($row = $query->fetch(\PDO::FETCH_NUM)) {
$path = $row[0];
$languageId = (int) $row[1];
$path = strlen($path) ? $sanitizer->pagePathName("/$path/", Sanitizer::toUTF8) : '/';
$paths[$languageId] = $path;
}
$query->closeCursor();
return $paths;
}
2022-03-08 15:55:41 +01:00
/**
* Given a page path, return the page ID or NULL if not found.
*
* @param string $path
* @return int|null
*
*/
public function getID($path) {
2022-11-05 18:32:48 +01:00
$id = $this->getPageId($path);
return $id ? $id : null;
}
/**
* Given a page path, return the page ID or 0 if not found.
*
* @param string|array $path
* @return int|null
* @since 3.0.186
*
*/
public function getPageID($path) {
$a = $this->getPageAndLanguageId($path);
return $a[0];
}
/**
* Given a page path return array of [ page_id, language_id ]
*
* If not found, returned page_id and language_id will be 0.
*
* @param string|array $path
* @return array
* @since 3.0.186
*
*/
public function getPageAndLanguageID($path) {
2022-03-08 15:55:41 +01:00
$table = self::dbTableName;
2022-11-05 18:32:48 +01:00
$database = $this->wire()->database;
$paths = is_array($path) ? array_values($path) : array($path);
$bindValues = array();
$wheres = array();
foreach($paths as $n => $path) {
$path = $this->wire()->sanitizer->pagePathName($path, Sanitizer::toAscii);
$path = trim($path, '/');
$wheres[] = "path=:path$n";
$bindValues["path$n"] = $path;
}
$where = implode(' OR ', $wheres);
$sql = "SELECT pages_id, language_id FROM $table WHERE $where LIMIT 1";
$query = $database->prepare($sql);
$row = array(0, 0);
foreach($bindValues as $bindKey => $bindValue) {
$query->bindValue(":$bindKey", $bindValue);
}
if(!$this->executeQuery($query)) return $row;
if($query->rowCount()) {
$row = $query->fetch(\PDO::FETCH_NUM);
}
$query->closeCursor();
return array((int) $row[0], (int) $row[1]);
}
/**
* Get page information about a given path
*
* Returned array includes the following:
*
* - `id` (int): ID of page for given path
* - `language_id` (int): ID of language path was for, or 0 for default language
* - `templates_id` (int): ID of template used by page
* - `parent_id` (int): ID of parent page
* - `status` (int): Status value for page ($page->status)
* - `path` (string): Path that was found
*
* @param string $path
* @return array|bool Returns info array on success, boolean false if not found
* @since 3.0.186
*
*/
public function getPageInfo($path) {
$sanitizer = $this->wire()->sanitizer;
$database = $this->wire()->database;
$languages = $this->wire()->languages;
$config = $this->wire()->config;
$table = self::dbTableName;
$useUTF8 = $config->pageNameCharset === 'UTF8';
if($languages && !$languages->hasPageNames()) $languages = null;
if($useUTF8) {
$path = $sanitizer->pagePathName($path, Sanitizer::toAscii);
}
$columns = array(
'pages_paths.path AS path',
'pages_paths.pages_id AS id',
'pages_paths.language_id AS language_id',
'pages.templates_id AS templates_id',
'pages.parent_id AS parent_id',
'pages.status AS status'
);
if($languages) {
foreach($languages as $language) {
if($language->isDefault()) continue;
$columns[] = "pages.status$language->id AS status$language->id";
}
}
$cols = implode(', ', $columns);
$sql =
"SELECT $cols FROM $table " .
"JOIN pages ON pages_paths.pages_id=pages.id " .
"WHERE pages_paths.path=:path";
$query = $database->prepare($sql);
$query->bindValue(':path', trim($path, '/'));
if(!$this->executeQuery($query)) return false;
$row = $query->fetch(\PDO::FETCH_ASSOC);
$query->closeCursor();
if(!$row) return false;
foreach($row as $key => $value) {
if($key === 'id' || strpos($key, 'status') === 0 || strpos($key, '_id')) {
$row[$key] = (int) $value;
}
}
if($useUTF8 && $row) {
$row['path'] = $sanitizer->pagePathName($row['path'], Sanitizer::toUTF8);
}
return $row;
}
/**
* Rebuild all paths table starting with $page and descending to its children
*
* @param Page|null $page Page to start rebuild from or omit to rebuild all
* @return int Number of paths added
* @since 3.0.186
*
*/
public function rebuild(Page $page = null) {
set_time_limit(3600);
$table = self::dbTableName;
if($page === null) {
// rebuild all
$this->wire()->database->exec("DELETE FROM $table");
$page = $this->wire()->pages->get('/');
}
$result = $this->updatePagePaths($page, true);
return $result;
2022-03-08 15:55:41 +01:00
}
/**
* Perform a path match for use by PageFinder
*
* @param DatabaseQuerySelect $query
* @param Selector $selector
* @throws PageFinderSyntaxException
*
*/
public function getMatchQuery(DatabaseQuerySelect $query, Selector $selector) {
static $n = 0;
2022-11-05 18:32:48 +01:00
$sanitizer = $this->wire()->sanitizer;
$database = $this->wire()->database;
2022-03-08 15:55:41 +01:00
$n++;
$table = self::dbTableName;
$alias = "$table$n";
$value = $selector->value;
2022-11-05 18:32:48 +01:00
$operator = $selector->operator;
2022-03-08 15:55:41 +01:00
// $joinType = $selector->not ? 'leftjoin' : 'join';
$query->join("$table AS $alias ON pages.id=$alias.pages_id");
2022-11-05 18:32:48 +01:00
if(in_array($operator, array('=', '!=', '<>', '>', '<', '>=', '<='))) {
2022-03-08 15:55:41 +01:00
if(!is_array($value)) $value = array($value);
$where = '';
foreach($value as $path) {
if($where) $where .= $selector->not ? " AND " : " OR ";
2022-11-05 18:32:48 +01:00
$path = $sanitizer->pagePathName($path, Sanitizer::toAscii);
$path = $database->escapeStr(trim($path, '/'));
$where .= ($selector->not ? "NOT " : "") . "$alias.path{$operator}'$path'";
2022-03-08 15:55:41 +01:00
}
$query->where("($where)");
} else {
if(is_array($value)) {
2022-11-05 18:32:48 +01:00
$error = "Multi value using '|' is not supported with path/url and '$operator' operator";
2022-03-08 15:55:41 +01:00
throw new PageFinderSyntaxException($error);
}
if($selector->not) {
2022-11-05 18:32:48 +01:00
$error = "NOT mode isn't yet supported with path/url and '$operator' operator";
2022-03-08 15:55:41 +01:00
throw new PageFinderSyntaxException($error);
}
/** @var DatabaseQuerySelectFulltext $ft */
$ft = $this->wire(new DatabaseQuerySelectFulltext($query));
2022-11-05 18:32:48 +01:00
$ft->match($alias, 'path', $operator, trim($value, '/'));
2022-03-08 15:55:41 +01:00
}
}
2022-11-05 18:32:48 +01:00
/*** PROTECTED API **********************************************************************************/
2022-03-08 15:55:41 +01:00
/**
2022-11-05 18:32:48 +01:00
* Updates path for page and all children
2022-03-08 15:55:41 +01:00
*
2022-11-05 18:32:48 +01:00
* @param Page|int $page
* @param bool|null $hasChildren Does this page have children? Specify false if known not to have children, true otherwise.
* @param array $paths Paths indexed by language ID, use index 0 for default language.
2022-03-08 15:55:41 +01:00
* @return int Number of paths updated
2022-11-05 18:32:48 +01:00
* @since 3.0.186
2022-03-08 15:55:41 +01:00
*
*/
2022-11-05 18:32:48 +01:00
protected function updatePagePaths($page, $hasChildren = null, array $paths = array()) {
static $level = 0;
2022-03-08 15:55:41 +01:00
2022-11-05 18:32:48 +01:00
$rootPageId = $this->wire()->config->rootPageID;
$database = $this->wire()->database;
$sanitizer = $this->wire()->sanitizer;
$languages = $this->getLanguages();
2022-03-08 15:55:41 +01:00
$table = self::dbTableName;
$numUpdated = 1;
2022-11-05 18:32:48 +01:00
$homeDefaultName = '';
$rebuildRoot = false;
$level++;
if($hasChildren === null) {
$hasChildren = $page instanceof Page ? $page->numChildren > 0 : true;
}
if(empty($paths)) {
// determine the paths
if(!is_object($page) || !$page instanceof Page) {
throw new WireException('Page object required on first call to updatePagePaths');
}
$pageId = $page->id;
if($page->parent_id === $rootPageId) $rebuildRoot = true;
if($languages) {
// multi-language
foreach($languages as $language) {
$languageId = $language->isDefault() ? 0 : $language->id;
$paths[$languageId] = $page->localPath($language);
if($pageId === 1 && !$languageId) $homeDefaultName = $page->name;
}
} else {
// single language
$paths[0] = $page->path();
}
} else {
// $paths already populated
$pageId = (int) "$page";
}
if($pageId === $rootPageId) $rebuildRoot = true;
// sanitize and prepare paths for DB storage
foreach($paths as $languageId => $path) {
$path = $sanitizer->pagePathName($path, Sanitizer::toAscii);
$paths[$languageId] = trim($path, '/');
}
$sql =
"INSERT INTO $table (pages_id, language_id, path) " .
"VALUES(:pages_id, :language_id, :path) " .
"ON DUPLICATE KEY UPDATE " .
"pages_id=VALUES(pages_id), language_id=VALUES(language_id), path=VALUES(path)";
2022-03-08 15:55:41 +01:00
$query = $database->prepare($sql);
2022-11-05 18:32:48 +01:00
$query->bindValue(":pages_id", $pageId, \PDO::PARAM_INT);
foreach($paths as $languageId => $path) {
$query->bindValue(":language_id", $languageId, \PDO::PARAM_INT);
$query->bindValue(":path", $path);
if($this->executeQuery($query)) $numUpdated += $query->rowCount();
}
2022-03-08 15:55:41 +01:00
if($hasChildren) {
2022-11-05 18:32:48 +01:00
if($homeDefaultName && $homeDefaultName !== 'home' && empty($paths[0])) {
// for when homepage has a name (lang segment) but it isn’ t used on actual homepage
// but is used on children
$paths[0] = $homeDefaultName;
}
$numUpdated += $this->updatePagePathsChildren($pageId, $paths);
}
if($level === 1 && $numUpdated > 0) {
$this->message(
sprintf($this->_n('Updated %d path', 'Updated %d paths', $numUpdated), $numUpdated),
Notice::admin
);
}
$level--;
if($rebuildRoot && !$level) $this->rebuildRootSegments();
2022-03-08 15:55:41 +01:00
2022-11-05 18:32:48 +01:00
return $numUpdated;
}
/**
* Companion to updatePagePaths method to handle children
*
* @param int $pageId
* @param array $paths Paths indexed by language ID, index 0 for default language
* @return int
* @since 3.0.186
*
*/
protected function updatePagePathsChildren($pageId, array $paths) {
$database = $this->wire()->database;
$languages = $this->getLanguages();
$nameColumns = array('pages.name AS name');
$numUpdated = 0;
2022-03-08 15:55:41 +01:00
2022-11-05 18:32:48 +01:00
if($languages) {
foreach($languages as $language) {
if($language->isDefault()) continue;
$nameColumns[] = "pages.name$language->id AS name$language->id";
2022-03-08 15:55:41 +01:00
}
}
2022-11-05 18:32:48 +01:00
$sql =
"SELECT pages.id AS id, " . implode(', ', $nameColumns) . ", " .
"COUNT(children.id) AS kids " .
"FROM pages " .
"LEFT JOIN pages AS children ON children.id=pages.parent_id " .
"WHERE pages.parent_id=:id " .
"GROUP BY pages.id ";
2022-03-08 15:55:41 +01:00
2022-11-05 18:32:48 +01:00
$query = $database->prepare($sql);
$query->bindValue(":id", $pageId, \PDO::PARAM_INT);
$rows = array();
if(!$this->executeQuery($query)) return $numUpdated;
while($row = $query->fetch(\PDO::FETCH_ASSOC)) {
$rows[] = $row;
}
$query->closeCursor();
2022-03-08 15:55:41 +01:00
2022-11-05 18:32:48 +01:00
foreach($rows as $row) {
$childPaths = array();
foreach($paths as $languageId => $path) {
$key = $languageId ? "name$languageId" : "name";
$name = !empty($row[$key]) ? $row[$key] : $row["name"];
$childPaths[$languageId] = "$path/$name";
}
$numUpdated += $this->updatePagePaths((int) $row['id'], $row['kids'] > 0, $childPaths);
}
2022-03-08 15:55:41 +01:00
return $numUpdated;
}
2022-11-05 18:32:48 +01:00
/*** ROOT SEGMENTS ******************************************************************************/
/**
* Is given segment/page name a root segment?
*
* A root segment is one that is owned by the homepage or a direct parent of the homepage, i.e.
* /about/ might be a root page segment and /de/ might be a root language segment. If it is a
* root page segment like /about/ then this will return the ID of that page. If it is a root
* language segment like /de/ then it will return the homepage ID (1).
*
* @param string $segment Page name string or path containing it
* @return int Returns page ID or 0 for no match.
* @since 3.0.186
*
*/
public function isRootSegment($segment) {
$segment = trim($segment, '/');
if(strpos($segment, '/')) list($segment,) = explode('/', $segment, 2);
$rootSegments = $this->getRootSegments();
$key = array_search($segment, $rootSegments);
if($key === false) return 0;
$key = ltrim($key, '_');
if(strpos($key, '.')) {
list($pageId, /*$languageId*/) = explode('.', $key, 2);
} else {
$pageId = $key;
}
return (int) $pageId;
}
/**
* Get root segments
*
* @param bool $rebuild
* @return array
* @since 3.0.186
*
*/
public function getRootSegments($rebuild = false) {
if(empty($this->rootSegments) || $rebuild) $this->rebuildRootSegments();
return $this->rootSegments;
}
/**
* Rebuild root segments stored in module config
*
* @since 3.0.186
*
*/
protected function rebuildRootSegments() {
$database = $this->wire()->database;
$config = $this->wire()->config;
$languages = $this->getLanguages();
$cols = array('id', 'name');
$segments = array();
if($languages) {
foreach($languages as $language) {
if(!$language->isDefault()) $cols[] = "name$language->id";
}
}
$sql = 'SELECT ' . implode(',', $cols) . ' FROM pages WHERE parent_id=:id ';
if($languages) $sql .= 'OR id=:id';
$query = $database->prepare($sql);
$query->bindValue(':id', $config->rootPageID, \PDO::PARAM_INT);
$query->execute();
while($row = $query->fetch(\PDO::FETCH_ASSOC)){
$id = (int) $row['id'];
unset($row['id']);
foreach($row as $col => $name) {
if(!strlen($name)) continue;
if($id === 1 && $col === 'name' && $name === Pages::defaultRootName) continue; // skip "/home/"
$col = str_replace('name', '', $col);
if(strlen($col)) {
$segments["_$id.$col"] = $name; // _pageID.languageID i.e. 123.456
} else {
$segments["_$id"] = $name; // _pageID i.e. 123
}
}
}
$query->closeCursor();
$this->rootSegments = $segments;
$this->wire()->modules->saveConfig($this, 'rootSegments', $segments);
return $segments;
}
/*** LANGUAGES **********************************************************************************/
/**
* Returns Languages object or false if not available
*
* @return Languages|false
*
*/
public function getLanguages() {
if($this->languages !== null) return $this->languages;
$languages = $this->wire()->languages;
if(!$languages) {
$this->languages = false;
} else if($languages->hasPageNames()) {
$this->languages = $languages;
} else {
$this->languages = false;
}
return $this->languages;
}
/**
* @param Language|int|string $language
* @return int Returns language ID or 0 for default language
* @since 3.0.186
*
*/
protected function languageId($language) {
$language = $this->language($language);
if(!$language->id || $language->isDefault()) return 0;
return $language->id;
}
/**
* @param Language|int|string $language
* @return Language|NullPage
* @since 3.0.186
*
*/
protected function language($language) {
$languages = $this->getLanguages();
if(!$languages) return new NullPage();
if(is_object($language)) return ($language instanceof Language ? $language : new NullPage());
return $languages->get($language);
}
/*** MODULE MAINT *******************************************************************************/
/**
* Execute a query/PDOStatement
*
* @param \PDOStatement $query
* @param bool $throw Allow exceptions to be thrown? (default=true)
* @return bool
* @throws \PDOException|WireException
*
*/
protected function executeQuery($query, $throw = true) {
try {
$result = $query->execute();
} catch(\Exception $e) {
if(!$this->checkTableSchema()) {
if($throw) throw $e;
$this->error($e->getMessage(), Notice::superuser | Notice::log);
}
$result = false;
}
return $result;
}
/**
* Check db schema
*
* @return bool True if changes made, false if not
*
*/
protected function checkTableSchema() {
$table = self::dbTableName;
$database = $this->wire()->database;
if(!$database->columnExists($table, 'language_id')) {
$sqls = array(
"ALTER TABLE $table ADD language_id INT UNSIGNED NOT NULL DEFAULT 0 AFTER pages_id",
"ALTER TABLE $table DROP PRIMARY KEY, ADD PRIMARY KEY(pages_id, language_id)",
"ALTER TABLE $table ADD INDEX language_id (language_id)",
"ALTER TABLE $table DROP INDEX path, ADD UNIQUE KEY path(path(500), language_id)",
);
foreach($sqls as $sql) {
$database->exec($sql);
}
$this->message("Added language_id column to table $table", Notice::admin);
return true;
}
return false;
}
/**
* Upgrade module
*
* @param $fromVersion
* @param $toVersion
* @since 3.0.186
*
*/
public function ___upgrade($fromVersion, $toVersion) {
if($fromVersion && $toVersion) {} // ignore
$this->checkTableSchema();
$this->rebuildRootSegments();
}
2022-03-08 15:55:41 +01:00
/**
* Install the module
*
*/
public function ___install() {
$table = self::dbTableName;
2022-11-05 18:32:48 +01:00
$database = $this->wire()->database;
$engine = $this->wire()->config->dbEngine;
$charset = $this->wire()->config->dbCharset;
2022-03-08 15:55:41 +01:00
$database->query("DROP TABLE IF EXISTS $table");
2022-11-05 18:32:48 +01:00
$sql =
"CREATE TABLE $table (" .
"pages_id int(10) unsigned NOT NULL, " .
"language_id int unsigned NOT NULL DEFAULT 0, " .
"path text CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL, " .
"PRIMARY KEY (pages_id, language_id), " .
"UNIQUE KEY path (path(500), language_id), " .
"INDEX language_id (language_id), " .
"FULLTEXT KEY path_fulltext (path)" .
") ENGINE=$engine DEFAULT CHARSET=$charset";
2022-03-08 15:55:41 +01:00
$database->query($sql);
}
/**
* Uninstall the module
*
*/
public function ___uninstall() {
2022-11-05 18:32:48 +01:00
$this->wire()->database->query("DROP TABLE " . self::dbTableName);
}
/**
* Module config
*
* @param InputfieldWrapper $inputfields
*
*/
public function getModuleConfigInputfields(InputfieldWrapper $inputfields) {
$session = $this->wire()->session;
$input = $this->wire()->input;
$numPages = 0;
$numRows = -1;
if($input->requestMethod('POST')) {
if($input->post('_rebuild')) $session->setFor($this, 'rebuild', true);
} else {
$numPages = $this->wire()->pages->count("id>0, include=all");
if($session->getFor($this, 'rebuild')) {
$session->removeFor($this, 'rebuild');
$timer = Debug::timer();
$this->rebuild();
$elapsed = Debug::timer($timer);
$this->message(sprintf($this->_('Completed rebuild in %d seconds'), $elapsed), Notice::noGroup);
} else {
$table = self::dbTableName;
$query = $this->wire()->database->prepare("SELECT COUNT(*) FROM $table");
if($this->executeQuery($query, false)) {
$numRows = (int) $query->fetchColumn();
$query->closeCursor();
}
}
}
$f = $inputfields->InputfieldCheckbox;
$f->attr('name', '_rebuild');
$f->label = sprintf($this->_('Rebuild page paths index for %d pages'), $numPages);
$f->label2 = $this->_('Rebuild now');
if($numPages) $f->description =
$this->_('Estimated rebuild time is up to 5 seconds per 1000 pages.') . ' ' .
sprintf($this->_('There are %d pages to process.'), $numPages);
if($numRows > 0) {
$f->notes = sprintf($this->_('There are currently %d rows stored by this module (path paths and versions of path paths).'), $numRows);
} else if($numRows === 0 && $input->requestMethod('GET')) {
$this->warning($this->_('Please choose the “rebuild now” option to create your page paths index.'));
}
$inputfields->add($f);
2022-03-08 15:55:41 +01:00
}
}