Get plugin config values without providing prefix or fallback

On plugin creation, itā€™s common to use let the user set config values with c::set and c::get.

Itā€™s also nice to have a plugin name prefix and a fallback value like this:

c::get('myplugin.hello', 'world');

When using c::get in very many places in the plugin, it can be a bit annoying to always include the a plugin name prefix and a fallback. It takes up space in the code every time and if you want to change the fallback, it needs to be done in several places.

Here is my solution for it:

I think the namespace is important to prevent function collisions.

namespace MyNamespace;
use c;

function setOption($name, $data) {
    $data = c::get('myplugin.' . $name, $data);
    kirby()->set('option', 'myplugin.' . $name, $data);
}

function getOption($name) {
    return kirby()->get('option', 'myplugin.' . $name);
}

What it does is that it put c::get data into kirby()->get() to use the correct fallback and store it globally. I see now that there is even more room for improvement, but it works.

In another file, set the values with fallback:

The benefit of it is that you only need to set this ones and then it will always be available with getOption later.

namespace MyNamespace;

setOption('log', false);
setOption('slug', 'hello-world');
setOption('token', 'token');

In the plugin somewhere, get the option needed without the need to send prefix or fallback:

namespace MyNamespace;

echo getOption('log');
echo getOption('slug');
echo getOption('token');

Another way would be to do something like the modules plugin does.
You can then use your settings within the same namespace like so:

$directory = Settings::directory();

I did it almost like that at first, but not as a singleton class. The pitfall was that I needed to create an instance of an option class everywhere. Also the list of options takes up a lot of space when having a function for each option. My approach is a bit more compact.

Anyway, a singleton class is better than a none singleton class in this case. Nice with alternatives! :slight_smile:

Yeah without a singleton class this would be a mess.
In the end itā€™s about own preferences is guess :slight_smile:

With the way you address the problem one could actually just import all settings from an array. Probably a plus for alot of options.

1 Like

Yep, Iā€˜d do it with an array and a magic __callStatic() method as well if the Modules plugin had more options. But for those few options the separate methods are actually simpler.

By the way: A singleton and a static class are two different things. :slight_smile:

1 Like

Iā€™ve taken both @lukaskleinschmidt @lukasbestle approaches and made something new out of it:

namespace PluginName;
use c;

class settings {
    public static function __callStatic($name, $args) {
        // Set prefix
        $prefix = 'plugin.name.';

        // Set config names and fallbacks as settings
        $settings = [
            'log'   => false,
            'slug'  => 'sync',
            'token' => 'token',
        ];

        // If config settings exists, return the config with fallback
        if(isset($settings) && array_key_exists($name, $settings)) {
            return c::get($prefix . $name, $settings[$name]);
    }
}

In the config.php file you can add something like this:

c::set('plugin.name.log', 'logfile.txt');

And get it inside the plugin with:

echo settings::log();

I think it ended up beautifully. Any improvement appreciated.

I think I will name this new babyā€¦ ā€œLukasā€ :baby:

Update: I added array_key_exists to also allow NULL values to be used

1 Like

Are you maintaining this anywhere? For a new plugin, I was looking for ā€˜best practicesā€™ on how to handle plugin settings w/o callback/default values - and this looks just great!

Not so much yet, but I donā€™t think it will need that much maintenance. It should work.

I have an issue for it here: https://github.com/jenstornell/kirby-secrets/issues/20

As a secret I think it will be even simpler to copy paste and give instructions around it.

Thatā€™s what I had in mind, just any kind of documentingā€¦

And if I wanted to loop over these settings and add each as option to say $someMethod, would that work like:

<?php
class Settings {

  // ...
  $settings = [
    'option1' => true,
    'option2' => 'some-string',
    'option3' => ['array1', 'array2'],
    'option4' => ['value1' => 'key1', 'value2' => 'key2'],
  ];

  // ...
}

namespace My\Namespace;

use Settings;

<?php

foreach ($settings as $setting => $key)
  $someMethod->$setting = settings::$key;
}

??? Doesnā€™t work!

maybe magical @texnixe knows and might share!

The $settings variable only exists within the magic method, you canā€™t access it from outside. Unless you would define the $settingsproperty outside of that function and make it available from outside via a method. But that would completely defeat the purpose, because then you would get the default array, but not the settings in your config. Why do you need to loop through that array?

Note that you donā€™t use use within the same namespace.

Alright, thanks for letting me know!

Have a good night everyone.

I now use an updated version of this code. It has a normal class and a static wrapper class to simplify the function call. Itā€™s a copy right out of a plugin Iā€™m working on. You should probably change the namespace name, the default values and the prefix.

<?php
namespace JensTornell\ComponentKit;
use c;

class SettingsClass {
    private $prefix = 'plugin.component.kit';
    private $defaults = [
        'route' => 'component-kit',
        'lock' => false,
        'js' => false,
        'css' => false
    ];

    public function get($name) {
        return c::get($this->prefix . '.' . $name, $this->defaults[$name]);
    }
}

// Wrapper static class
class settings {
    public static function get($name) {
        $SettingsClass = new SettingsClass($name);
        return $SettingsClass->get($name);
    }
    public static function __callStatic($name, $args) {
        $SettingsClass = new SettingsClass($name);
        return $SettingsClass->get($name);
    }
}

echo settings::route(); // Will echo component-kit
  • By default the echo settings::route() will output component-kit as it is a default value.
  • You can override it by adding the config c::set('plugin.component.kit.route', 'my-route'); in config.php.
  • On all pages where you use settings::route() you also need the namespace on top.

@S1SYPHOS. Not sure if the above will help you.

Update

I added a get function to the settings class. Itā€™s now possible to do things like settings::get('my.option'); including dots.