cosmicsafari Posted July 3, 2017 Posted July 3, 2017 Hi all, I have a module which creates numerous fields, pages etc. I would like to disable the ability to uninstall the module if any of the generated pages have children, as a mistaken uninstall could really mess up any website which is using it. Im curious about what is the best way to achieve this, currently I have some like: public function ___uninstall(){ error_log('---- UNINSTALL!! ----'); //check to see if any config pages have been added and abort uninstall if true //to avoid uninstalling and losing any work which has been done up to this point. if($this->canWeUninstall()) { //remove pages $this->deletePages($this->cPages->getPages()); //remove templates and field groups $this->deleteTemplates($this->cTemplates->getTemplates()); //remove repeaters $this->deleteRepeaters($this->cRepeaters->getRepeaters()); //delete fields $this->deleteFields($this->cFields->getFields(), $this->cRepeaters->getRepeaters()); } else { error_log('Uninstall aborted because config settings exist!'); $this->error('Whoops! Module cant be uninstalled as it appears to be in use.'); return; } } This works in the sense that it doesn't remove any of the generated content, which is good as it wont break the website. However it still shows the module as uninstalled, I can achieve what i'm looking for by replacing 'return' with 'die' but that results in a white page and looks rather rubbish so its not really a great solution. I would imagine there must be a better way to achieve this, any thoughts? Would it be possible to do this check via a hook before uninstallation and abort before we get to the point of running the uninstall() method, as I imagine that is what updates the DB to turn the module off so to speak?
BitPoet Posted July 3, 2017 Posted July 3, 2017 I think you just need to make sure you don't return from ___uninstall. Throwing an exception should be sufficient, though I haven't tested it. if(! $this->canWeUninstall()) { throw new WireException("Whoops! Module cant be uninstalled as it appears to be in use."); } 2
cosmicsafari Posted July 4, 2017 Author Posted July 4, 2017 13 hours ago, BitPoet said: I think you just need to make sure you don't return from ___uninstall. Throwing an exception should be sufficient, though I haven't tested it. if(! $this->canWeUninstall()) { throw new WireException("Whoops! Module cant be uninstalled as it appears to be in use."); } That works a treat, thanks man! 1
bernhard Posted July 12, 2019 Posted July 12, 2019 This is what I came up with today: I have a main module that installs 3 other modules (via module info "installs" => ["mod1", "mod2", "mod3"]). Uninstall was a bit of a problem, because it tried to uninstall a fieldtype module and this was not possible when I had an existing field of that type. Throwing an exception did also not work, because all submodules where uninstalled even if the main module threw an exception. I then tried to throw an exception in all of the submodules as well, but that was a mess and did not work reliably. Hooks to the rescue: public function init() { $this->addHookBefore("Modules::uninstall", $this, "customUninstall"); } /** * Custom uninstall routine * * @param HookEvent $event */ public function customUninstall($event) { $class = $event->arguments(0); if($class != 'yourmodulename') return; // set flag $abort = false; // check1 if($this->check1() == false) { $this->error('check1 failed'); $abort = true; } // check2 if($this->check2() == false) { $this->error('check2 failed'); $abort = true; } // uninstall? if($abort) { // there where some errors $event->replace = true; // prevents original uninstall $this->session->redirect("./edit?name=$class"); // prevent "module uninstalled" message } } Real life example that also checks if the uninstalled module is the main module or a sub-module. If it is a sub-module it shows an error and redirects to the config screen of the main module: public function init() { $this->addHookBefore("Modules::uninstall", $this, "customUninstall"); } /** * Custom uninstall routine * * @param HookEvent $event */ public function customUninstall($event) { $installs = $this->getModuleInfo(); $class = $event->arguments(0); $url = "./edit?name=$class"; // exit when class does not match if(!in_array($class, $installs)) return; // intercept uninstall $abort = false; // if it is not the main module we redirect to the main module's config if($class != 'RockMarkup') { $abort = true; $url = "./edit?name=RockMarkup"; $this->error('Please uninstall the main module'); } // check if any fields exist $fields = $this->wire->fields->find('type=FieldtypeRockMarkup')->count(); if($fields > 0) { $this->error('Remove all fields of type RockMarkup before uninstall!'); $abort = true; } // on uninstall of the main module we remove this hook so that it does // not interfere with the auto-uninstall submodules if($class == 'RockMarkup') $event->removeHook(null); // uninstall? if($abort) { // there where some errors $event->replace = true; // prevents original uninstall $this->session->redirect($url); // prevent "module uninstalled" message } } 1
Gadgetto Posted February 25, 2020 Posted February 25, 2020 On 7/12/2019 at 5:37 PM, bernhard said: Real life example that also checks if the uninstalled module is the main module or a sub-module. If it is a sub-module it shows an error and redirects to the config screen of the main module: Hi @bernhard, I have the same situation and just stumbled across your post here! Great solution! Where do I setup this hook? In main module or the submodule?
bernhard Posted February 25, 2020 Posted February 25, 2020 Hi @Gadgetto you can have a look here: https://github.com/BernhardBaumrock/RockMarkup2/blob/c184febcd92c75b329b9eba1e2b53caa088e0a94/RockMarkup2.module.php#L110 Does that help?
Gadgetto Posted February 25, 2020 Posted February 25, 2020 11 minutes ago, bernhard said: Hi @Gadgetto you can have a look here: https://github.com/BernhardBaumrock/RockMarkup2/blob/c184febcd92c75b329b9eba1e2b53caa088e0a94/RockMarkup2.module.php#L110 Does that help? I see you placed the hook into the main modules init method. But how is this hook triggered when someone tries to uninstall the submodule?
bernhard Posted February 25, 2020 Posted February 25, 2020 It's triggered by all uninstalls of modules that are based on the main module (like RockTabulator is based on RockMarkup2). And those modules extend the main module and therefore the init method is called on every load of the submodule.
Gadgetto Posted February 25, 2020 Posted February 25, 2020 6 minutes ago, bernhard said: It's triggered by all uninstalls of modules that are based on the main module (like RockTabulator is based on RockMarkup2). And those modules extend the main module and therefore the init method is called on every load of the submodule. Hmm.. my FieldType module (and the two other submodules) isn't based on the main module so it seems I need to place the hook into the FieldType module?
bernhard Posted February 25, 2020 Posted February 25, 2020 I've read my post above and I'm not sure if I was offtopic at that time or if my post 10min ago was not 100% correct. I'm working hard on my DateRange field though, so I've no time for digging into that. What is your exact scenario?
Gadgetto Posted February 25, 2020 Posted February 25, 2020 I'm developing a module which comes with 3 other integrated (and required) modules. On of them is a custom selector FieldType which gets its data from a helper class within the main module. The problem is if one wants to uninstall the main module but wants to preserve the pages which uses the custom selector FieldType, the uninstallation process is interrupted as this FieldType is still in use. I first thought to simply let the FieldType installed (standalone), but it has dependencies in a helper class which won't work when main module is uninstalled.
bernhard Posted February 25, 2020 Posted February 25, 2020 Yeah, I guess PW's module dependency features are too limited for such cases. I think you'd need to remove the dependencies in the module's info array and implement them on your own somewhere in the modules' install() and uninstall() methods. 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now