0

In OctoberCMS, I would like to change a page process simply by attaching a different plugin component.

I have a plugin component (makeform) which inserts a form (defined in a database table).
Clicking the form's submit button calls onSubmit() which calls process().
process() is a function defined in another plugin component.

i) Can I call process() from within makeform without knowing the name of the other plugin or its component? That is, without having to use 'Acme\Plugin\Components\ProcessForm', 'processForm';

ii) Alternatively, can I programmatically discover the name of the other attached component and it's plugin, and then somehow specify it's process() function?

iii) Or is it a case of using a static properties dropdown to choose which process, and then adding the component dynamically. Always assuming I can $this->addComponent('Acme\Plugin\Components\ProcessForm', 'processForm'); beyond init().


Edit: Experimentation

I was hoping to dynamically addComponent().
Wherever I place it, in init() or elsewhere, I get the error:

Class name is not registered for the component "Acme\Plugin\Components\ProcessForm". Check the component plugin.

Even if I'm not using one of it's classes.
Many online references to this error message, but not one that has helped me.

Edit: Further explanation

A (hopefully) simplified explanation of what I'm trying to achieve.

In essence I imagine a page process consisting of a string of components.
Each component calls a function in the next component until the process ends.
The overall process can be modified simply by replacing components.
I am guessing the only way to connect components is by standardizing the function names. So this (probably?) requires components to belong to particular stages of the process, although it would be ideal if each of them can fit in at any stage (where appropriate).

illustration

AlanQ
  • 91
  • 1
  • 12
  • maybe like this? https://stackoverflow.com/questions/37855845/how-do-i-call-a-component-inside-a-component-octobercms – Peter Haberkorn Oct 30 '17 at 05:58
  • Thank you again @peter-haberkorn. I have come across this question in my searches, but don't understand how to use `addComponent`: I just get the error message quoted in my question. It does _look_ like the elegant solution I'm searching for. – AlanQ Oct 31 '17 at 16:34

2 Answers2

0

I think the best approach would be to define another property in which you set the namespace of the plugin.

public function defineProperties(){
  'pluginName' => [
    'label' => 'Plugin Namespace to call process method from',
    'type' => 'text'
  ]
}

--

public function onSubmit(){
  $plugin = $this->property('pluginName');
  $plugin::process($formData);
}

In this way you keep the component logic clean from any hardcoded plugin names.

Edit: 30/10/17

I'm not sure there's a way to list all available components inside the application. An alternative is to set up a Settings page, with a repeater of sorts in which you declare all available components with namespaces.

You than parse this to an array inside the onSubmit method and return this to the dropdown.

public function defineProperties(){
  'components' => [
    'label' => 'Plugin Namespace to call process method from',
    'type' => 'dropdown',
    'options' => 'getComponentsOptions' // optional but easier to understand
  ]
}

public function getComponentsOptions(){
  $components = Settings::get('components');
  $options = [];

  foreach ($components as $component)
  {
    $options[$component['namespace']] = $component['name'];
  }

  return $options;
}

/Models/Settings/fields.yaml

fields:
    components:
        type: repeater
        form:
            fields:
                name:
                    placeholder: My Component Name
                    span: left
                namespace:
                    placeholder: Acme\Name\Components\MyComponent;
                    span: right

/Models/Settings.php

class Settings extends Model
{
    public $implement = ['System.Behaviors.SettingsModel'];
    // A unique code
    public $settingsCode = 'acme_name_settings';
    // Reference to field configuration
    public $settingsFields = 'fields.yaml';
}

http://octobercms.com/docs/plugin/settings#introduction

  • Thankyou @cptmeatball. Your 2nd piece of code is certainly a neat way to specify the function. [Although I needed `(new $plugin)->process();`]. Using your solution, I replaced the text property with a static dropdown as per my third option, without needing `addComponent`. Ideally, I'm looking for a solution that allows the admin to simply drag'n'drop the component from the backend components list (or, failing that, to choose one from an auto-populated Properties dropdown) without needing to _know_ the NameSpace. – AlanQ Oct 27 '17 at 23:01
0
  1. extend the base component class and add your function und let the components extends from this?

  2. make a new helper class with the function maybe call it static or so

  3. add a global function https://octobercms.com/forum/post/global-php-classesfunctions

Peter Haberkorn
  • 259
  • 1
  • 9
  • Thank you @peter-haberkorn, an interesting approach. It's beyond my level of experience for the moment. I'm sure the solution is tantalizingly simple. I have modified my question to add some clarity. – AlanQ Oct 30 '17 at 01:56