pwFoo Posted October 8, 2014 Share Posted October 8, 2014 Hi,I would like to build plugins with conditional autoload dependent on loaded modules.Topic: ProcessWire Dev Branch - 3. Conditional autoload modules 3. Conditional autoload modules. In PHP 5.3+, modules may now specify an anonymous function OR a selector string, rather than a boolean for the 'autoload' property returned by getModuleInfo(). PW runs the anonymous function after determining the current $page, so your module can make autoload decisions based on the $page (or any other factor you'd like), if desired. Lets say that we have a module that we only want to autoload when the template is 'admin': public static function getModuleInfo() { return array( 'title' => 'Module Title', 'summary' => 'Summary text...', 'version' => 1, 'autoload' => function() { if(wire('page')->template == 'admin') return true; else return false; }); } And the same example but using a selector for autoload: public static function getModuleInfo() { return array( 'title' => 'Module Title', 'summary' => 'Summary text...', 'version' => 1, 'autoload' => 'template=admin' ); } I tried that simple function code inside getModuleInfo(). [...] 'requires' => array('UserFrontendRegister'), 'autoload'=> function() { return class_exists('UserFrontendRegister',false); }, [...] Class_exists was suggested to check if a module is loaded. That works fine inside a template, but not with my module / autoload function. I think the module is NOT loaded during this code is executed, but I'm not sure... Is such a conditional autoload possible? Link to comment Share on other sites More sharing options...
Raymond Geerts Posted October 8, 2014 Share Posted October 8, 2014 (edited) I havent tested but you could try: 'autoload'=> function() { return wire('modules')->isInstalled('UserFrontendRegister'); }, Edit: changed wire('module') to wire('modules')... my bad Edited October 8, 2014 by Raymond Geerts 1 Link to comment Share on other sites More sharing options...
pwFoo Posted October 8, 2014 Author Share Posted October 8, 2014 Yes, should work, but isn't my needed case I need to check if the module is loaded instead of just installed. Here a example class_exists('UserFrontendRegister',false); // return false $modules->get('UserFrontendRegister') class_exists('UserFrontendRegister',false); // return true As autoload condition it could be used to load a register plugin only if the register module / page is active. Use template or page as selector is possible, but not as flexible as a class_exists check. Link to comment Share on other sites More sharing options...
sforsman Posted October 8, 2014 Share Posted October 8, 2014 After ProcessWire has finished the ready-stage, none of the conditional autoloads are evaluated again (the list of them is even cleared). This means that if you load a module in a template, you are already past the ready-stage and hence no autoloading conditionals will be processed. 3 Link to comment Share on other sites More sharing options...
pwFoo Posted October 8, 2014 Author Share Posted October 8, 2014 Hello sforsman, please read my first post with Ryans examples I only tested the class_exists function inside a template and it works as expected. As an autoload function inside getModuleInfo() it doesn't work. Link to comment Share on other sites More sharing options...
Wanze Posted October 8, 2014 Share Posted October 8, 2014 This won't work, because in the static method getModuleInfo() there is no guarantee that the API is already available. See: https://github.com/wanze/ProcessBatcher/issues/1 Cheers 1 Link to comment Share on other sites More sharing options...
sforsman Posted October 8, 2014 Share Posted October 8, 2014 (edited) please read my first post with Ryans examples I have read it. My point is that during ProcessWire bootstrapping, the class does not exist yet, and the existence (i.e. your conditional autoloading function) won't be checked after ProcessWire becomes ready() Edit: Just to make this clear - the only thing you have when your conditional autoloading function is called is a placeholder module, the actual class hasn't been included yet - so it doesn't exist (unless it's an autoloading module or your module cache is empty). It will be included and replaced when you request the module inside your template - but like I have said, this does not trigger any conditional autoloading for other modules. This won't work, because in the static method getModuleInfo() there is no guarantee that the API is already available. See: https://github.com/wanze/ProcessBatcher/issues/1 Cheers There is guarantee for the conditional autoloads - they are triggered when ProcessWire goes ready(). Edited October 8, 2014 by sforsman 5 Link to comment Share on other sites More sharing options...
pwFoo Posted October 8, 2014 Author Share Posted October 8, 2014 3. Conditional autoload modules. In PHP 5.3+, modules may now specify an anonymous function OR a selector string, rather than a boolean for the 'autoload' property returned by getModuleInfo(). PW runs the anonymous function after determining the current $page, so your module can make autoload decisions based on the $page (or any other factor you'd like), if desired. Lets say that we have a module that we only want to autoload when the template is 'admin': After ProcessWire has finished the ready-stage, none of the conditional autoloads are evaluated again (the list of them is even cleared). This means that if you load a module in a template, you are already past the ready-stage and hence no autoloading conditionals will be processed. Got it! I think not the conditional autoload was the problem, but the main module is loaded after conditional autoload decision... Link to comment Share on other sites More sharing options...
sforsman Posted October 8, 2014 Share Posted October 8, 2014 Got it! I think not the conditional autoload was the problem, but the main module is loaded after conditional autoload decision... Oh, do you mean that you are just trying to see if a module is installed? And if so, you want another module to be loaded? Link to comment Share on other sites More sharing options...
Soma Posted October 8, 2014 Share Posted October 8, 2014 Maybe worth reading https://processwire.com/talk/topic/5477-check-if-a-module-is-loaded/ Link to comment Share on other sites More sharing options...
sforsman Posted October 8, 2014 Share Posted October 8, 2014 By the way the order does not matter if your main module is not an autoloading module. Its real class is not loaded until the module is requested in the template. You will only have a placeholder that is created based on the cache, without including the main module's code. 1 Link to comment Share on other sites More sharing options...
pwFoo Posted October 8, 2014 Author Share Posted October 8, 2014 Maybe worth reading https://processwire.com/talk/topic/5477-check-if-a-module-is-loaded/ Hi Soma, I know this post and tried to use Ryans Code example as autoload condition By the way the order does not matter if your main module is not an autoloading module. Its real class is not loaded until the module is requested in the template. You will only have a placeholder that is created based on the cache, without including the main module's code. The main module isn't an autoload module. I don't know how PW handles or cache this. Link to comment Share on other sites More sharing options...
sforsman Posted October 8, 2014 Share Posted October 8, 2014 Pwfoo, in that case, like I have mentioned, the class will not exist until your main module's file is included, which happens only when you actually request the module (for an example with $wire->modules->get("MainModule")). Link to comment Share on other sites More sharing options...
Soma Posted October 8, 2014 Share Posted October 8, 2014 Sorry wasn't reading carefully. Maybe if you can provide more what you want to archive, maybe there's better alternative ways. It's also good to know that if you change the autoload setting in code you have to refresh module cache or reinstall module. Link to comment Share on other sites More sharing options...
pwFoo Posted October 8, 2014 Author Share Posted October 8, 2014 @sforsman Ok, thanks. So I have to find another way @Soma No problem, thanks for reading and answer here I have a register user module loaded inside a template and now try to (auto-)load an plugin / extension (here an example / test notification module) via conditional autoload. public static function getModuleInfo() { return array( 'title' => 'UserFrontendRegisterNotification', 'summary' => 'Enable Emails to Registration', 'version' => '001', 'requires' => array('UserFrontendRegister'), 'autoload'=> function() { return class_exists('UserFrontendRegister',false); }, ); } The notification module hooks into the register method after a user is successful registered. I wouldn't autoload the register notifications on every page, but if the register module is loaded. So a conditional autoload (see above) looks like the best solution. Unfortunately that way doesn't work Here the example addHook from example module notifications public function init() { $this->addHookAfter('UserFrontendRegister::executeRegister',$this,'sendEmail'); } The conditional autoload should load the notifications module only if the register module is loaded. During init() the submodule / plugin hooks into the "main module". Any other resource friendly method to do that? Link to comment Share on other sites More sharing options...
pwFoo Posted October 8, 2014 Author Share Posted October 8, 2014 A working solution at the moment is a autoload if the main module is installed. 'autoload'=> function() { return wire('modules')->isInstalled('UserFrontendRegister'); }, And add a hook after register process at init(). $this->addHookAfter('UserFrontendRegister::executeRegister',$this,'sendEmail'); I know this solution, but tried to find a way to reduce loading of not needed modules. Link to comment Share on other sites More sharing options...
Soma Posted October 8, 2014 Share Posted October 8, 2014 After all I think it depends a lot on what context and how it's used. If in templates, a call to the main module (which is not autoload), you can't use the autoload condition, unless you also trigger something from the template which is not that nice. In the end I think a conditional autoload also requires some "resources" so loading a simple module that only has hooks anyway, might not be as bad you think. As far as I know modules that hook into something need to be "autoload" anyway, if using a condition or not doesn't really matter and is a ok tradeoff? Not sure if I'm overlooking something obvious. Of course it's a good thinking in the first place to not waste resources, would be good to maybe have some sort of data to show what impact autoload really has when there's 100's of additonal modules? I'm also curious how Ryan would see this, I can't remember there was ever something in more depth about this. Anybody care to test? Link to comment Share on other sites More sharing options...
sforsman Posted October 8, 2014 Share Posted October 8, 2014 A working solution at the moment is a autoload if the main module is installed. 'autoload'=> function() { return wire('modules')->isInstalled('UserFrontendRegister'); }, And add a hook after register process at init(). $this->addHookAfter('UserFrontendRegister::executeRegister',$this,'sendEmail'); I know this solution, but tried to find a way to reduce loading of not needed modules. The funny thing is, ProcessWire works like this for the exact same reason: to reduce loading of not needed modules If you really, really want to do this yourself, then you would have to create a container inside the main module (or create a new module), that holds the relationships (this can even be a module configuration field). Then each "sub" module registers themselves as a conditionally loadable module with the main module. This would be done inside their ___install() -method. Then in your main module's init(), you fetch all the registered "sub" modules and load them. This would work - I can even write you an example. But to be honest, I'd just autoload the damn the module Though just let me know if you still want an example of what I described. 6 Link to comment Share on other sites More sharing options...
Nico Knoll Posted October 8, 2014 Share Posted October 8, 2014 @sforsman: Thanks for your great answers in the forum recently! Looks like you have a lot of knowledge about PW even with only 50 posts in the forum Keep on doing the good stuff 6 Link to comment Share on other sites More sharing options...
kongondo Posted October 8, 2014 Share Posted October 8, 2014 What Nico said! My thoughts exactly! . 1 Link to comment Share on other sites More sharing options...
sforsman Posted October 9, 2014 Share Posted October 9, 2014 @sforsman: Thanks for your great answers in the forum recently! Looks like you have a lot of knowledge about PW even with only 50 posts in the forum Keep on doing the good stuff What Nico said! My thoughts exactly! . Wow ok, thanks for the encouraging comments guys I've worked with PW for quite a while, surfing the core silently in the background (I'm a little shy like that). But one day apeisa gave me a proper kick in the knee and told me to grow a pair - I did, ergo, here I am. I must say you have a really good thing going on here and I'm very happy to be part of it! 7 Link to comment Share on other sites More sharing options...
pwFoo Posted October 9, 2014 Author Share Posted October 9, 2014 @sforsman Thank you for helping here! If you really, really want to do this yourself, then you would have to create a container inside the main module (or create a new module), that holds the relationships (this can even be a module configuration field). Then each "sub" module registers themselves as a conditionally loadable module with the main module. This would be done inside their ___install() -method. Then in your main module's init(), you fetch all the registered "sub" modules and load them. This would work - I can even write you an example. Ok, got the way it works. Interesting and nice way. Dependent on the quantity of plugins it could be better, but I should keep it simple first... So I start with a simple conditional autoload (module is installed). Would like to see example code, too. But wouldn't waste your time to write the code Link to comment Share on other sites More sharing options...
sforsman Posted October 14, 2014 Share Posted October 14, 2014 Would like to see example code, too. But wouldn't waste your time to write the code Hey pwFoo! It's no trouble really. Check the code with examples from here https://github.com/sforsman/AutoloadContainer 1 Link to comment Share on other sites More sharing options...
tpr Posted January 12, 2017 Share Posted January 12, 2017 Just for the info this can be used to autoload only if the template of the edited page in the admin is "basic-page": 'autoload' => function() { return wire('pages')->get(wire('input')->get->id)->template == 'basic-page'; }, 1 1 Link to comment Share on other sites More sharing options...
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