Populate select field with function call (data-*@)

I’m trying to populate a select field in a blueprint with entries from a list field in a plugin configuration.

Consider this excerpt of blueprint.yaml of plugin Foo:

fields:
    bar:
        type: list
        fields:
            .id:
                type: text
                label: "ID"
            .value:
                type: text
                label: "Value"

Now, in a page blueprint, I’d like to have a select field that lists all bar items via their id. I don’t think this is possible with config-*@ syntax, but reading through the documentation on blueprint function calls (data-*@) makes me believe it should be possible this way. However, from the documentation, I don’t understand how to call upon a function from plugin Foo. Here is what I tried:

header.baz:
    type: select
    label: "Baz"
    data-options@: '\Grav\Plugin\Foo::myStaticFunc'

Where the foo.php has the appropriate function (currently just returning dummy data):

public static function myStaticFunc()
{
    // Obviously, this should actually fetch the configuration
    // and then get and return all `id` values of items in `bar`
    return ["some", "values", "please"];
}

I thought this might work, as the documentation has this example: '\Grav\Plugin\Admin::route'. However, the above did not yield any values in the select field. Thinking that I might return the wrong type, I also tried the same with an associative array, to no avail. I’m thinking the error might be in how I call the function, so I also tried the following without success (I’m just guessing at this point):

  • '\Grav\Plugin\Foo\Foo::myStaticFunc'
  • '\Grav\Plugins\Foo::myStaticFunc'
  • '\Grav\Plugins\Foo\Foo::myStaticFunc'
  • '\Grav\Common\Plugin\Foo::myStaticFunc'
  • '\Grav\Common\Plugin\Foo\Foo::myStaticFunc'

Hence, I hope you can help me to figure out…

  • What is the correct syntax and is that documented somewhere?
  • What data structure would a function need to return for data-options@, an array?

@domsson, You may have named the plugin ‘Foo’, but the php class will be named ‘FooPlugin’. In the blueprint, you should be referencing the name of the class, not the name of the plugin.

So try the following:

data-options@: '\Grav\Plugin\FooPlugin::myStaticFunc'
1 Like

Thank you, @anon76427325 - that did the trick. To summarize, here is how it worked:

Blueprint:

data-options@: '\Grav\Plugin\FooPlugin::myStaticFunc'

foo.php:

public static function myStaticFunc()
{
    return ["some" => "Some", "values" => "Values", "please" => "Please"];
}

I ran into this scenario again and found this post of myself. However, I was left with one more question: How to get the plugin configuration from within PHP?

Now, I’m not sure this is the best way (probably not), but this will do the trick:

public static function myStaticFunc()
{
    $pluginName = "whatever_the_name";
    $pluginConfig = Grav::instance()["config"]["plugins"][$pluginName];
    $desiredData = $pluginConfig["foo"];
    return $desiredData;
}

This has at least one issue, though: the hard-coded plugin name. In a non-static function, we could use $this->name, but $this isn’t available in a static context. If someone knows a way around this, please let me know.

@domsson, Would you mind explaining why using a hardcoded plugin name is an issue?

Presumably it would be more broadly applicable if it was dynamic. That’s not possible though because of the context, as you noted @domsson. You can, however, parametrize the method:

data-default@: ['\Grav\Plugin\FooPlugin::myStaticFunc', 'pluginname']

With:

public static function myStaticFunc($pluginName)
{
    return Grav::instance()['config']->get(
        'plugins.' . $pluginName. '.arrayOfStuff',
        ['' => 'None']
    );
}

The second parameter of the get()-method is the default value. It would also be pertinent to check the shape of the retrieved data before returning it, as the user could have broken an expected associated array.

The benefit of the getter is that you won’t be getting errors about arrays. Stacking accessors in the form of ["config"]["plugins"][$pluginName]["foo"] will fail if any of the keys do not exist, rather than fallback to null.

1 Like

@anon76427325 I shouldn’t have used the word “issue”, really. After all, a plugin’s name occurs all over the place, from directory and file names to class names. However, I do like to keep my code as dynamic as possible wherever that is an option.

To name just one possible benefit here: it would make for easily reusable code. Or, to phrase it differently, it might prevent issues resulting from copy & paste of existing code.

@OleVik thank you, those are great suggestions.

@domsson, OK, fair enough.

By the way, I presume OleVik meant the following syntax to get the config:

Grav::instance()['config']->get();
1 Like

Oh, indeed! I’ll correct that, thanks.