Jump to content

Storing module config using API


ffub
 Share

Recommended Posts

Hi,

I'm writing a few modules that use Oauth rather than your usual API keys. I need to store the token after the user is returned to the backend. I can figure out how to make the module configurable using the getModuleConfigInputfields class, but is there a way of setting one of these options via the API and having it stored in the DB?

Many thanks,

Stephen

  • Like 1
Link to comment
Share on other sites

To save module config data, put the data you want to save in an array and then call the $modules API var with the saveModuleConfigData function.

<?php

$data = array(
   'something' => 'Well hello there',
   'something_else' => 1234,
   ); 

$module = 'ModuleClassName'; // can also be instance of module

wire('modules')->saveModuleConfigData($module, $data); 

ProcessWire will automatically set the keys from your configData to the module when it loads, so you don't have to do anything else. As a result, your module could call upon a value like $this->something; and the value would be there.

Or if you want, you can add a setConfigData(array $data) function to your module, and it will set the config data to that instead (when the module is loaded). Though I rarely do this.

To retrieve a module's config data from another module or elsewhere in the API, you can also use $modules->getModuleConfigData('ModuleClassName');  Use it like this:

<?php
$data = wire('modules')->getModuleConfigData('ModuleClassName'); 
echo $data['something']; // displays 'Well hello there'

The $data would be the same array that you set in the first example.

  • Like 3
Link to comment
Share on other sites

  • 2 months later...

I tried to save some default settings on install this way within the ___install() method of a module:

$config = array(
'user_roles' => $this->roles->get('guest')
);
$this->modules->saveModuleConfigData($this, $config);

When trying to get the config data on module execution, I just got an empty array. Any idea why it shouldn’t work this way?

$module = $this->modules->get($module_page->process);
$config = $this->modules->getModuleConfigData(get_class($module));
Link to comment
Share on other sites

I think in this case it's because the getModuleConfigData is happening in the same request as the saveModuleConfigData. I'm guessing that if you performed a getModuleConfigData on the next request, you'd see it there.

The reason for this is that anything in your config data gets populated to the module automatically when it is initialized. Your module could expect to find a $this->user_roles property locally present on the next request. Once the config data has been loaded, it gets cached. That cache only gets cleared once per page view. So the empty array you are getting is most likely because the old (empty) data is cached, but the new data would appear on the next request. It would make sense for saveModuleConfigData to clear that cache, so you'll see that in the next commit.

Since your config data is automatically set to the module when it gets loaded, the getModuleConfigData is something that isn't needed often. getModuleConfigData is mainly useful for modifying existing config data right before you saveModuleConfigData.

I also want to add that configData can't have objects in it. So your $this->roles->get('guest') will likely get converted to the ID (number) of the guest role.

Link to comment
Share on other sites

While the saveModuleConfigData is called from the install() method of the module, getModuleConfigData is called from a method of another module in a completely different context. And it never happens on a single page view. So I don’t think that’s the problem here. Any other idea?

Saving the role’s ID is what I want to happen. I see, I forgot to set it to $this->roles->get('guest')->id.

EDIT:

I also call saveModuleConfigData from another method somewhere else. Like this:

$this->modules->saveModuleConfigData($this->pages->get($this->input->get->id)->process, $config);

Data isn’t saved. I double-checked the parameters, process field is correct, $config is an associative array, everything looks fine. So what’s wrong?

UDPATE: I actually found out, that it isn’t a problem with saving the data. It’s just not loaded. My module has this data stored in the db:

{"user_roles":["37","1008"],"consumer_key":"asdsadsdsad","consumer_secret":"xasdhaduhu"}

But the values aren’t accessible via $this->user_roles or $this->consumer_key in the module.

Link to comment
Share on other sites

Oliver, I should have asked this before (sorry): Does your module implement the "ConfigurableModule" interface? ProcessWire doesn't consider it configurable unless it implements that interface. If you are extending the WireData class, it already implements the interface, so all you have to do is change:

class MyModule extends WireData {

To this:

class MyModule extends WireData implements ConfigurableModule {

The point of having this interface is so that PW doesn't spend additional cycles looking for and populating configuration data for modules that don't use it (as most don't).

Link to comment
Share on other sites

The module extends Process and Process extends WireData, doesn’t it? Shouldn’t the module inherit the implementation from WireData?

EDIT: Ok, I read it slower a second time. I think, you got the problem, you got me! ;)

EDIT: It works. Thanks once more, ryan!

Link to comment
Share on other sites

  • 3 weeks later...

Got another problem here that may be a bug. I’m working on a configurable module and it’s getModuleConfigInputfields method returns a multiple select field for selecting roles. After being processed, the value submitted as an array of course is turned into a PageArray object. When the data is saved in the executeEdit part of ProcessModules, saveModuleConfigData tries to save it as an encoded object within {}. But it doesn’t succeed in storing the actual page IDs, so the config field stays empty. So, I think a PageArray should be saved either as a string (the __toString result separated by “|”) or actually as an encoded array “[id,id,id]”.

Link to comment
Share on other sites

Oliver, could I get a copy of the getModuleConfigInputfields function you are using so that I can test with it locally? Feel free to just extract the relevant part and post here or email to me at ryan at this domain name. I just wanted to make sure I'm getting the context of this right.

Link to comment
Share on other sites

Of course.

As I am a lazy guy, I took the existing roles field to create the input field with all the roles as options from it. I created an own static function for it, that is part of a management module and returns the field - as it is a default - to its child modules, which use it in their config field form.

Method in management module:

   public static function getRoleConfigField($user_roles) {
	    // prepare roles
	    $roles = Wire::getFuel('roles');
	    if(!is_array($user_roles)) {
		    $user_roles = explode("|", $user_roles);
	    }
	    $value = new PageArray();
	    if(is_array($user_roles)) {
		    foreach($user_roles as $role) {
			    $value->add($roles->get($role));
		    }
	    }
	    // offer user roles to choose
	    $roles_field = Wire::getFuel('fields')->get('roles');
	    $field = $roles_field->getInputfield(Wire::getFuel('page'), $roles_field);
	    $field->label = __("User roles", __FILE__);
	    $field->description = __("Roles given to users created for this type of login by default", __FILE__);
	    $field->value = $value;
	    $field->name = 'user_roles';
	    return $field;	   

   } 

getModuleConfigInputfields

 public static function getModuleConfigInputfields(array $data) {
 $modules = Wire::getFuel('modules');	   
 $fields = new InputfieldWrapper();
    // roles
    $field = ProcessSocialLoginManager::getRoleConfigField($data['user_roles']);
    if($field->name) {
	    $fields->add($field);
    }

    // consumer key
    $field = $modules->get('InputfieldText');
    $field->name = 'consumer_key';
    $field->label = __('Twitter Consumer Key', __FILE__);
    $field->description = __('Enter the consumer key you got for your site from dev.twitter.com', __FILE__);
    $field->value = $data['consumer_key'];
    $fields->add($field);
    // consumer secret
    $field = $modules->get('InputfieldText');
    $field->name = 'consumer_secret';
    $field->label = __('Twitter Consumer Secret', __FILE__);
    $field->description = __('Enter the consumer secret you got for your site from dev.twitter.com', __FILE__);
    $field->value = $data['consumer_secret'];
    $fields->add($field);
    return $fields;
}
Link to comment
Share on other sites

Thanks Oliver. I think the issue here is this:

// offer user roles to choose
$roles_field = Wire::getFuel('fields')->get('roles');
$field = $roles_field->getInputfield(Wire::getFuel('page'), $roles_field); // HERE
$field->label = __("User roles", __FILE__);
$field->description = __("Roles given to users created for this type of login by default", __FILE__);
$field->value = $value;
$field->name = 'user_roles';
return $field; 

Note the line I labeled 'HERE'. You are asking it to get an inputfield for the 'roles' field in the context of $page. At that time, $page is /processwire/modules/ (template admin) and that page has no 'roles' field. So I think this is unpredictable. Instead, I would suggest doing this:

// offer user roles to choose
$field = wire('modules')->get('InputfieldCheckboxes');
$field->attr('name', 'user_roles');
$field->label = __('User Roles'));
$field->description = __("Roles given to users created for this type of login by default");
foreach(wire('roles') as $role) $field->addOption($role->id, $role->name);  
$field->attr('value', $user_roles); 

Just tested here and it works. Also, unrelated, but had a couple other things I wanted to mention:

Wire::getFuel('something') is the same as wire('something'). The wire('something') is newer syntax, and you'll usually see the older syntax in the core. But I find wire('something') easier to read, so just wanted to mention that you don't have to use Wire::getFuel() unless you want to. :)

For language translation, __('something'); and __('something', __FILE__); are equivalent. Specifying the __FILE__ saves a little overhead, as PW doesn't need to figure it out on it's own. But for something like a module config, or even your own site templates, it probably doesn't matter much. I've mainly been including the __FILE__ part in getModuleInfo() functions because those do have potential to be called on each request, so every little optimization helps there. Note that none of this is applicable to the $this->_('something'); syntax, but if course that syntax can't be used in a static function.

For the top of your getModuleConfigInputfields($data) function, I recommend including something like this:

$defaultData = array(
'user_roles' => array(),
'consumer_key' => '',
'consumer_secret' => '',
);
$data = array_merge($defaultData, $data);

That initializes defaults and makes any corresponding values in $data overwrite them (if present). But if values aren't present, then you don't have to worry about PHP complaining about uninitialized indexes when you are in PW debug mode.

  • Like 1
Link to comment
Share on other sites

  • 4 years later...

Is it today still necessary to store a module configuration variable like this?

<?php

$data = array(
   'something' => 'Well hello there',
   'something_else' => 1234,
   ); 

$module = 'ModuleClassName'; // can also be instance of module

wire('modules')->saveModuleConfigData($module, $data);
//I can store a new value in the config variable, but it´s not stored...
$this->set("module_config_variable","new value"))
Link to comment
Share on other sites

Thanks Adrian,

I wrote a save() function for my module...
 

public function save() {

	// get stored data
	$data = wire('modules')->getModuleConfigData($this);

	// populate stored data array with the current data
	foreach($data as $name => $value)
		$data[$name]=$this->$name;

	// save config data
		 wire('modules')->saveModuleConfigData($this, $data);
	
	return $data; // or return true or whatever you like
}

so I can use it in my module like this:
 

//as example storing a GET variable
$this->id = $this->wire('input')->get('id');
$this->save();
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...