1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-09 16:26:59 +02:00

Add new hooks: Pages::trashReady(), Pages::deleteBranchReady(), Pages::deletedBranch(). The deleteBranch hooks cover the case of recursive deletions where an entire branch of pages is deleted. For those cases, these hooks can be more useful than the regular deleteReady() and deleted() hooks because those two are called for every single page, rather than just for the initiating page.

This commit is contained in:
Ryan Cramer
2020-07-17 14:43:33 -04:00
parent 63a59e2317
commit 6a1b6a21ae
3 changed files with 90 additions and 22 deletions

View File

@@ -8,7 +8,7 @@
* *
* This is the most used object in the ProcessWire API. * This is the most used object in the ProcessWire API.
* *
* ProcessWire 3.x, Copyright 2019 by Ryan Cramer * ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* https://processwire.com * https://processwire.com
* *
* @link http://processwire.com/api/variables/pages/ Offical $pages Documentation * @link http://processwire.com/api/variables/pages/ Offical $pages Documentation
@@ -49,10 +49,13 @@
* @method added(Page $page) Hook called when a new page has been added. * @method added(Page $page) Hook called when a new page has been added.
* @method moved(Page $page) Hook called when a page has been moved from one parent to another. * @method moved(Page $page) Hook called when a page has been moved from one parent to another.
* @method templateChanged(Page $page) Hook called when a page template has been changed. * @method templateChanged(Page $page) Hook called when a page template has been changed.
* @method trashReady(Page $page) Hook called when a page is about to be moved to the trash.
* @method trashed(Page $page) Hook called when a page has been moved to the trash. * @method trashed(Page $page) Hook called when a page has been moved to the trash.
* @method restored(Page $page) Hook called when a page has been moved OUT of the trash. * @method restored(Page $page) Hook called when a page has been moved OUT of the trash.
* @method deleteReady(Page $page) Hook called just before a page is deleted. * @method deleteReady(Page $page, array $options) Hook called just before a page is deleted.
* @method deleted(Page $page) Hook called after a page has been deleted. * @method deleted(Page $page, array $options) Hook called after a page has been deleted.
* @method deleteBranchReady(Page $page, array $options) Hook called before a branch of pages deleted, on initiating page only.
* @method deletedBranch(Page $page, array $options, $numDeleted) Hook called after branch of pages deleted, on initiating page only.
* @method cloneReady(Page $page, Page $copy) Hook called just before a page is cloned. * @method cloneReady(Page $page, Page $copy) Hook called just before a page is cloned.
* @method cloned(Page $page, Page $copy) Hook called after a page has been successfully cloned. * @method cloned(Page $page, Page $copy) Hook called after a page has been successfully cloned.
* @method renamed(Page $page) Hook called after a page has been successfully renamed. * @method renamed(Page $page) Hook called after a page has been successfully renamed.
@@ -1677,6 +1680,18 @@ class Pages extends Wire {
} }
} }
/**
* Hook called when a Page is about to be trashed
*
* @param Page $page
* @since 3.0.163
*
*/
public function ___trashReady(Page $page) {
if($page) {} // ignore
}
/** /**
* Hook called when a page has been moved to the trash * Hook called when a page has been moved to the trash
* *
@@ -1733,9 +1748,11 @@ class Pages extends Wire {
* #pw-hooker * #pw-hooker
* *
* @param Page $page Page that is about to be deleted. * @param Page $page Page that is about to be deleted.
* @param array $options Options passed to delete method (since 3.0.163)
* *
*/ */
public function ___deleteReady(Page $page) { public function ___deleteReady(Page $page, array $options = array()) {
if($options) {} // ignore
foreach($this->types as $manager) { foreach($this->types as $manager) {
if($manager->hasValidTemplate($page)) $manager->deleteReady($page); if($manager->hasValidTemplate($page)) $manager->deleteReady($page);
} }
@@ -1747,10 +1764,12 @@ class Pages extends Wire {
* #pw-hooker * #pw-hooker
* *
* @param Page $page Page that was deleted * @param Page $page Page that was deleted
* @param array $options Options passed to delete method (since 3.0.163)
* *
*/ */
public function ___deleted(Page $page) { public function ___deleted(Page $page, array $options = array()) {
$this->log("Deleted page", $page); if($options) {}
if(empty($options['_deleteBranch'])) $this->log("Deleted page", $page);
/** @var WireCache $cache */ /** @var WireCache $cache */
$cache = $this->wire('cache'); $cache = $this->wire('cache');
$cache->maintenance($page); $cache->maintenance($page);
@@ -1759,6 +1778,40 @@ class Pages extends Wire {
} }
} }
/**
* Hook called before a branch of pages is about to be deleted, called on root page of branch only
*
* Note: this is called only on deletions that had 'recursive' option true and 1+ children.
*
* #pw-hooker
*
* @param Page $page Page that was deleted
* @param array $options Options passed to delete method
* @since 3.0.163
*
*/
public function ___deleteBranchReady(Page $page, array $options) {
if($page && $options) {}
}
/**
* Hook called after a a branch of pages has been deleted, called on root page of branch only
*
* Note: this is called only on deletions that had 'recursive' option true and 1+ children.
*
* #pw-hooker
*
* @param Page $page Page that was the root of the branch
* @param array $options Options passed to delete method
* @param int $numDeleted Number of pages deleted
* @since 3.0.163
*
*/
public function ___deletedBranch(Page $page, array $options, $numDeleted) {
if($page && $options) {}
$this->log("Deleted branch with $numDeleted page(s)", $page);
}
/** /**
* Hook called when a page is about to be cloned, but before data has been touched * Hook called when a page is about to be cloned, but before data has been touched
* *

View File

@@ -5,7 +5,7 @@
* *
* Implements page manipulation methods of the $pages API variable * Implements page manipulation methods of the $pages API variable
* *
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer * ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* https://processwire.com * https://processwire.com
* *
*/ */
@@ -1044,8 +1044,8 @@ class PagesEditor extends Wire {
* @param bool|array $recursive If set to true, then this will attempt to delete all children too. * @param bool|array $recursive If set to true, then this will attempt to delete all children too.
* If you don't need this argument, optionally provide $options array instead. * If you don't need this argument, optionally provide $options array instead.
* @param array $options Optional settings to change behavior: * @param array $options Optional settings to change behavior:
* - uncacheAll (bool): Whether to clear memory cache after delete (default=false) * - `uncacheAll` (bool): Whether to clear memory cache after delete (default=false)
* - recursive (bool): Same as $recursive argument, may be specified in $options array if preferred. * - `recursive` (bool): Same as $recursive argument, may be specified in $options array if preferred.
* @return bool|int Returns true (success), or integer of quantity deleted if recursive mode requested. * @return bool|int Returns true (success), or integer of quantity deleted if recursive mode requested.
* @throws WireException on fatal error * @throws WireException on fatal error
* *
@@ -1055,6 +1055,9 @@ class PagesEditor extends Wire {
$defaults = array( $defaults = array(
'uncacheAll' => false, 'uncacheAll' => false,
'recursive' => is_bool($recursive) ? $recursive : false, 'recursive' => is_bool($recursive) ? $recursive : false,
// internal use properties:
'_level' => 0,
'_deleteBranch' => false,
); );
if(is_array($recursive)) $options = $recursive; if(is_array($recursive)) $options = $recursive;
@@ -1062,22 +1065,30 @@ class PagesEditor extends Wire {
$this->isDeleteable($page, true); // throws WireException $this->isDeleteable($page, true); // throws WireException
$numDeleted = 0; $numDeleted = 0;
$numChildren = $page->numChildren;
$deleteBranch = false;
if($page->numChildren) { if($numChildren) {
if(!$options['recursive']) { if(!$options['recursive']) {
throw new WireException("Can't delete Page $page because it has one or more children."); throw new WireException("Can't delete Page $page because it has one or more children.");
} else foreach($page->children("include=all") as $child) {
/** @var Page $child */
if($this->pages->delete($child, true, $options)) {
$numDeleted++;
} else {
throw new WireException("Error doing recursive page delete, stopped by page $child");
} }
if($options['_level'] === 0) {
$deleteBranch = true;
$options['_deleteBranch'] = $page;
$this->pages->deleteBranchReady($page, $options);
}
foreach($page->children('include=all') as $child) {
/** @var Page $child */
$options['_level']++;
$result = $this->pages->delete($child, true, $options);
$options['_level']--;
if(!$result) throw new WireException("Error doing recursive page delete, stopped by page $child");
$numDeleted += $result;
} }
} }
// trigger a hook to indicate delete is ready and WILL occur // trigger a hook to indicate delete is ready and WILL occur
$this->pages->deleteReady($page); $this->pages->deleteReady($page, $options);
foreach($page->fieldgroup as $field) { foreach($page->fieldgroup as $field) {
if(!$field->type->deletePageField($page, $field)) { if(!$field->type->deletePageField($page, $field)) {
@@ -1099,7 +1110,7 @@ class PagesEditor extends Wire {
// delete entirely from pages_parents table // delete entirely from pages_parents table
$this->pages->parents()->delete($page); $this->pages->parents()->delete($page);
$database = $this->wire('database'); $database = $this->wire()->database;
$query = $database->prepare("DELETE FROM pages WHERE id=:page_id LIMIT 1"); // QA $query = $database->prepare("DELETE FROM pages WHERE id=:page_id LIMIT 1"); // QA
$query->bindValue(":page_id", $page->id, \PDO::PARAM_INT); $query->bindValue(":page_id", $page->id, \PDO::PARAM_INT);
$query->execute(); $query->execute();
@@ -1107,8 +1118,9 @@ class PagesEditor extends Wire {
$this->pages->sortfields()->delete($page); $this->pages->sortfields()->delete($page);
$page->setTrackChanges(false); $page->setTrackChanges(false);
$page->status = Page::statusDeleted; // no need for bitwise addition here, as this page is no longer relevant $page->status = Page::statusDeleted; // no need for bitwise addition here, as this page is no longer relevant
$this->pages->deleted($page); $this->pages->deleted($page, $options);
$numDeleted++; $numDeleted++;
if($deleteBranch) $this->pages->deletedBranch($page, $options, $numDeleted);
if($options['uncacheAll']) $this->pages->uncacheAll($page); if($options['uncacheAll']) $this->pages->uncacheAll($page);
$this->pages->debugLog('delete', $page, true); $this->pages->debugLog('delete', $page, true);

View File

@@ -5,7 +5,7 @@
* *
* Implements page trash/restore/empty methods of the $pages API variable * Implements page trash/restore/empty methods of the $pages API variable
* *
* ProcessWire 3.x, Copyright 2018 by Ryan Cramer * ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* https://processwire.com * https://processwire.com
* *
*/ */
@@ -45,10 +45,13 @@ class PagesTrash extends Wire {
throw new WireException("This page (id=$page->id) may not be placed in the trash"); throw new WireException("This page (id=$page->id) may not be placed in the trash");
} }
if(!$trash = $this->pages->get($this->config->trashPageID)) { $trash = $this->pages->get($this->config->trashPageID);
if(!$trash->id) {
throw new WireException("Unable to load trash page defined by config::trashPageID"); throw new WireException("Unable to load trash page defined by config::trashPageID");
} }
$this->pages->trashReady($page);
$page->addStatus(Page::statusTrash); $page->addStatus(Page::statusTrash);
if(!$page->parent->isTrash()) { if(!$page->parent->isTrash()) {