Jump to content


Photo

Storing module config using API


  • Please log in to reply
10 replies to this topic

#1 ffub

ffub

    Jr. Member

  • Members
  • PipPip
  • 37 posts
  • 20

  • LocationLondon, UK

Posted 16 November 2011 - 01:05 PM

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

#2 ryan

ryan

    Reiska

  • Administrators
  • 7,797 posts
  • 6573

  • LocationAtlanta, GA

Posted 16 November 2011 - 01:30 PM

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.






#3 Oliver

Oliver

    Sr. Member

  • Members
  • PipPipPipPip
  • 134 posts
  • 27

  • LocationBasel, Switzerland

Posted 13 February 2012 - 05:12 PM

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));


#4 ryan

ryan

    Reiska

  • Administrators
  • 7,797 posts
  • 6573

  • LocationAtlanta, GA

Posted 14 February 2012 - 09:29 AM

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.

#5 Oliver

Oliver

    Sr. Member

  • Members
  • PipPipPipPip
  • 134 posts
  • 27

  • LocationBasel, Switzerland

Posted 14 February 2012 - 04:02 PM

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.

#6 ryan

ryan

    Reiska

  • Administrators
  • 7,797 posts
  • 6573

  • LocationAtlanta, GA

Posted 15 February 2012 - 03:48 PM

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).

#7 Oliver

Oliver

    Sr. Member

  • Members
  • PipPipPipPip
  • 134 posts
  • 27

  • LocationBasel, Switzerland

Posted 15 February 2012 - 03:59 PM

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!

#8 Oliver

Oliver

    Sr. Member

  • Members
  • PipPipPipPip
  • 134 posts
  • 27

  • LocationBasel, Switzerland

Posted 04 March 2012 - 12:15 PM

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]”.

#9 ryan

ryan

    Reiska

  • Administrators
  • 7,797 posts
  • 6573

  • LocationAtlanta, GA

Posted 05 March 2012 - 12:45 PM

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.

#10 Oliver

Oliver

    Sr. Member

  • Members
  • PipPipPipPip
  • 134 posts
  • 27

  • LocationBasel, Switzerland

Posted 07 March 2012 - 04:55 PM

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;
}


#11 ryan

ryan

    Reiska

  • Administrators
  • 7,797 posts
  • 6573

  • LocationAtlanta, GA

Posted 08 March 2012 - 10:16 AM

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.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users