Jump to content
Robin S

getModuleConfigData() not working with separate config file

Recommended Posts

If I set my module config data the old-fashioned way, in the main module file with

public static function getModuleConfigInputfields(array $data) { ...

then I can get the config info successfully with

$modules->getModuleConfigData('myModule');

Edit: I was wrong about that - it only works if the config has been manually saved.

But if I set the module config in a separate file using the ModuleConfig class then getModuleConfigData() returns an empty array. Any idea what I'm doing wrong?

Update: I have got it working but it's still a bit strange. I can't get the config data if the module config page has never been saved (i.e. it is in its default state after install). Once I save the module config page I can get the data with getModuleConfigData(), even if I haven't changed anything from the default settings. A bug maybe?

Share this post


Link to post
Share on other sites

Not sure, but I think it is by design. You never can pull something from a DB without first having to save it into the DB. Or do I get something wrong with the issue?

  • Like 1

Share this post


Link to post
Share on other sites

Thanks. I was wrong about defining config with getModuleConfigInputfields() - I can't get the default config data with getModuleConfigData() unless the config page has been saved, and that applies to either method of setting the default config.

So if getModuleConfigData() only works if the module config page has been saved, how do I get the default config data if the module just been installed and the config had not been changed or saved? Any defaults set for the config work in the module exactly the same as if they had been manually set, so it's frustrating to need a different method for getting the default config. I guess we have to check to see if getModuleConfigInputfields() returns an empty array and if so check something else to get the default config.

The new way for setting module config extends a core ModuleConfig class, and contains a method getDefaults() that returns the config defaults in an array - this sounds like exactly what I need, but how do I call this method to get the defaults array? My objective is get the config data for one module inside another module.

Share this post


Link to post
Share on other sites

There were several ways how people do this. You can see it in most of the modules out there in the repos. I haven't read or tried a new method for this. My, maybe old-schooled way is something like this:

  • define default- or factorysettings in an array
  • merge them with the modules config settings in the ready method
  • keep them in a class var or write them back into the config settings

Depending on how you store it, you further can access your class var or pull it from modules config settings.

Example:

    private static $factorySettings = array(
        'var1' => 'value1',
        'var2' => false,
        'var3' => true
    );

    public function ready() {
        $this->data = array_merge(self::$factorySettings, wire('modules')->getModuleConfigData($this->className()));
        // optionally write it back         
        wire('modules')->saveModuleConfigData($this->className()), $this->data);
    }

A short version, only merging, without store it in a class var:

    public function ready() {
        wire('modules')->saveModuleConfigData($this->className()), array_merge(self::$factorySettings, wire('modules')->getModuleConfigData($this->className())));
    }

Haven't tested, but should be available then in install too. If not, try moving the above from the ready method into the init method.

Edited by horst
corrected config save method name

Share this post


Link to post
Share on other sites

I sincerely think this should be an implementation detail and not something the user should worry about, especially if it's a different behavior than the old-school config method.

Share this post


Link to post
Share on other sites

I sincerely think this should be an implementation detail and not something the user should worry about, especially if it's a different behavior than the old-school config method.

Yep, but it would need a standardized way how devs have to define the default values, or I'm wrong?

Do you know if something in this regard is in the pipeline?

Share this post


Link to post
Share on other sites

It doesn't. I mean is should just return the same data available through $this->myConfigValue, which in turn does (probably) only rely on the config inputfield names. Am I wrong on that? I mean the module does need to know about those values no matter if they are saved or defaults or anything else.

Share this post


Link to post
Share on other sites

For what is your "It doesn't." meant? For the "pipeline" or for the "standardized way" how devs have to define the defaults?

Robin_S asked for a way how it is possible to have the values available in the install method too. IMO this only can be done if the modules dev uses a standardized way to hardcode the default values into the modules file. Otherwise PW wouldn't be able to pick them up and merge with the configSettings. Once this is done, your suggestion is right and would be fine if PW do that automagically on init of a module.

Share this post


Link to post
Share on other sites

I cannot find any request to getting those default config settings while installing the module. The problem I got from the topic is that getModuleConfigData() will return no value for as long as the module's settings weren't (manually) saved once after a successful install, which is imho bad handling of an edgecase. And since the module can pick up any defaults to supply them to $this->configValue calls, I cannot see why we would need anything new to make getModuleConfigData() return a useful result right from the start.

  • Like 1

Share this post


Link to post
Share on other sites

how do I get the default config data if the module just been installed and the config had not been changed or saved?

Sorry, maybe I haven't said it 100% correct, but I meant this: when it is called the first time, so: when installing the module. (Maybe not directly in the install method)

---

I sincerely think this should be an implementation detail and not something the user should worry about, especially if it's a different behavior than the old-school config method.

It wasn't me who initially has said we need something new. :)

---

And since the module can pick up any defaults to supply them to $this->configValue calls, I cannot see why we would need anything new to make getModuleConfigData() return a useful result right from the start.

But back to the issue: I just try to understand what you are saying, but I'm missing a piece: Please can you point me to where the modules can pick up the default values? ???

Edited by horst

Share this post


Link to post
Share on other sites

But back to the issue: I just try to understand what you are saying, but I'm missing a piece: Please can you point me to where the modules can pick up the default values? ???

Since we are talking about the newish ModuleConfig class, which does not work for Robin: https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/ModuleConfig.php#L61-L68 

This will return the default values. The older static method way really seems to need a forced manual save. But for anyone not implementing this, the module would also not receive any default values, therefore the workaround is kinda necessary anyways.

And modules, which have "just been installed" are still already installed. I doubt we're talking about ___install() here, but even if we do, it should probably just work there, too, when using the ModuleClass.

Share this post


Link to post
Share on other sites
  • keep them in a class var or write them back into the config settings

...

A short version, only merging, without store it in a class var:
    public function ready() {
        wire('modules')->setModuleConfigData($this->className()), array_merge(self::$factorySettings, wire('modules')->getModuleConfigData($this->className())));
    }

Haven't tested, but should be available then in install too. If not, try moving the above from the ready method into the init method.

This would work, and it would be a solution if the module you want the config data for is one that you have created yourself. But most modules, whether they use the old or new way of setting config defaults, do not do this.

Since we are talking about the newish ModuleConfig class, which does not work for Robin: https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/ModuleConfig.php#L61-L68 

This will return the default values. The older static method way really seems to need a forced manual save.

The old and new way of setting module config perform the same as far as I can tell, in that both do not make the defaults available to getModuleConfigData() unless the module specifically saves them with setModuleConfigData(), which is what horst is suggesting. But it's not common for a module to actually do that. Modules do not need to force a manual save for either method, so long as you only care about making the default values available within the module itself.

The problem I got from the topic is that getModuleConfigData() will return no value for as long as the module's settings weren't (manually) saved once after a successful install, which is imho bad handling of an edgecase. And since the module can pick up any defaults to supply them to $this->configValue calls, I cannot see why we would need anything new to make getModuleConfigData() return a useful result right from the start.

I agree that it's desirable for getModuleConfigData() and getConfig() to return the config regardless of whether the config consists of the defaults or a manually saved variation to the defaults. It's not really an edge case because it's quite common to leave a module config at the defaults I think. For modules using the newer ModuleConfig class it seems like this should be possible because there is a standardised way of setting defaults. For modules using the older config I suspect this wouldn't be possible because of the variety of different ways defaults are stored and used inside those modules.

Back to my immediate problem: assuming the module I want the config defaults for uses the ModuleConfig class, how can I use the getDefaults() method to return the array of defaults? I can get the individual values by name like this...

$modules->getModule('MyModule')->my_value

...but I want the array of all values so I don't need to know and specify each by name.

The getDefaults() method is in the MyModuleConfig class, but that isn't a module itself so I can't do something like...

$modules->getModule('MyModuleConfig')->getDefaults()

But there must be some other way to access that method, right?

Share this post


Link to post
Share on other sites

.. The getDefaults() method is in the MyModuleConfig class, but that isn't a module itself so I can't do something like...

$modules->getModule('MyModuleConfig')->getDefaults()
But there must be some other way to access that method, right?

Not tested, but I assume you should get it with

$this->modules->getModule('NameOfYourModule')->getDefaults();
wire('modules')->getModule('NameOfYourModule')->getDefaults();

or within a module:

$this->getDefaults();

Share this post


Link to post
Share on other sites

A short version, only merging, without store it in a class var:

    public function ready() {
        wire('modules')->saveModuleConfigData($this->className()), array_merge(self::$factorySettings, wire('modules')->getModuleConfigData($this->className())));
    }

Haven't tested, but should be available then in install too. If not, try moving the above from the ready method into the init method.

setModuleConfigData is a protected function so it doesn't work. Even setting it to public for testing purposes, the default module config is not set after install.

Share this post


Link to post
Share on other sites

I am a bit lost here and am probably way off. To test things, I have installed my Blog module but did not do any manual save after that. My default settings are saved without doing any manual save...this is because I have this line in ProcessBlog...___install()

$this->wire('modules')->saveModuleConfigData($this, self::configDefaults());

...unless of course that is what you guys mean by manual save? :-)
 
I can immediately access the settings...e.g. did this in basic-page

$settings = $modules->getModuleConfigData('ProcessBlog');

Edit: forgot to add...I still use the old way of setting module config + PW 2.7.3

Edited by kongondo
  • Like 4

Share this post


Link to post
Share on other sites

setModuleConfigData is a protected function so it doesn't work. Even setting it to public for testing purposes, the default module config is not set after install.

This should be saveModuleConfigData() not setModuleConfigData() - thanks kongondo :)

$this->wire('modules')->saveModuleConfigData($this, self::configDefaults());

...unless of course that is what you guys mean by manual save? :-)

Yes, that's what we mean. :)

Or clicking "Save" on the module config screen.

Most modules that I have looked at don't do saveModuleConfigData() on install. Random example: TextformatterVideoEmbed

Not tested, but I assume you should get it with

$this->modules->getModule('NameOfYourModule')->getDefaults();
wire('modules')->getModule('NameOfYourModule')->getDefaults();

or within a module:

$this->getDefaults();

This doesn't work - getDefaults() is a method of the ModuleConfig class, or MyModuleConfig class which extends ModuleConfig. It's not a method in the module class.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks kongondo, saveModuleConfigData works fine. I guess @horst did a typo writing setModuleConfigData. Maybe he wrote the whole stuff by head? :)

  • Like 1

Share this post


Link to post
Share on other sites

Most modules that I have looked at don't do saveModuleConfigData() on install. Random example: TextformatterVideoEmbed

Sure. In Blog I had a very specific need hence implemented the save. I needed the initial settings before the user configured how they wanted to structure their blog...

Share this post


Link to post
Share on other sites

This works...

$module_config = new MyModuleConfig();
$defaults = $module_config->getDefaults();

Does that look okay?? I'm an OOP noob. :)

  • Thanks 1

Share this post


Link to post
Share on other sites

I'm digging this thread out because I just came across the same problem in my module. I fixed it for now by merging the default config as suggested by @Robin S:

$options = $this->modules->getModuleConfigData($this);
$defaults = (new TextformatterPageTitleLinksConfig())->getDefaults();
$options = array_merge($defaults, $options);

See the complete source code here.

However, I agree that this should be handled by ProcessWire. I expected getModuleConfigData to return the final merged configuration, the method doesn't suggest that it only retrieves the config that has been saved to the database. This way the method creates a temporary dead zone between installing a module and saving the module configuration page, where errors can pop up in the meantime.

@horst @kongondo By the way, saving the module config during installation may not be sufficient. In my case, I got an error when I upgraded my module to version 3.0.0 which included a new setting. So even though the module was already installed and the options had been saved before, the new version was missing the new configuration option as it wasn't included in the configuration returned by getModuleConfigData. So with this approach one may also need to hook into the upgrade process to make sure the configuration is saved after every update.

  • Like 5

Share this post


Link to post
Share on other sites
On 1/2/2020 at 4:52 PM, MoritzLost said:

However, I agree that this should be handled by ProcessWire. I expected getModuleConfigData to return the final merged configuration, the method doesn't suggest that it only retrieves the config that has been saved to the database.

Isn't that why there's getConfig and saveConfig now?

Share this post


Link to post
Share on other sites

@LostKobrakai I don't think so, it appears the old name (getModuleConfigData) is simply an alias to the getConfig function now. See the source code of the Modules class. I tested it with the current dev version of ProcessWire, and the problem described above still occurs. Also, the source of getConfig pretty much only fetches the config from the correct database row, without merging in the default config (which I believe it should do as well) ...

  • Like 1

Share this post


Link to post
Share on other sites

If you are using the separate ModuleConfig class method you can use it like this:

// Get module config.
// (Holds merged data from DB and default config. 
// This works because of using the ModuleConfig class)
$moduleConfig = $this->wire('modules')->get('ModuleName');

// You can than access the keys like this:
$value = $moduleConfig->name_of_key;

 

  • Like 1

Share this post


Link to post
Share on other sites

@Gadgetto That doesn't work in all cases though. My module allows you to call it's main method with custom arguments, overwriting any configuration option for this method call only. If I were accessing the module config through the magic __get properties, that would mean I'd have to check for overwrites anywhere I need to access an option, making the code overly complicated. Right now I'm merging the passed options with the module configuration and then merging the defaults in manually. In my opinion, the second step should be done by getModuleConfigData automatically.

  • Like 1

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...