I am very new to Drupal and I am asked to create form with a submit button and a service that makes a get request to an API with the values from the form. The API is a simple API that the user can enter a country and it will return a response with the correct greeting from that country.

This is my routing file.

  path: '/hello'
    _controller: Drupal\hello_world\Controller\HelloWorldSalutation::salutation
    _form: Drupal\hello_world\Form\GreetingForm
    _title: 'Get a greeting from a different language'
    _permission: 'administer site configuration'

First problem is that I do not know how to make the form and the controller in the same routing, and second is that I do not know how to invoke that service when the user has entered submit.

This is the services file.

    class: Drupal\hello_world\HelloWorldSalutation
    arguments: [ '@config.factory' ,'@tempstore.private']
    class: Drupal\Core\Cache\CacheBackendInterface
      - { name: cache.bin }
    factory: [ '@cache_factory', 'get' ]
    arguments: [ nameofbin ]

I will skip some lines from the GreetingFrom class to keep it simple, but I can add them if it is required.

Here is the submitForm function from the GreetingForm class. The idea is to put the input in a global tempstore so I cal access the values from the controller I guess.

  public function submitForm(array &$form, FormStateInterface $form_state)
    $search_str = $form_state->getValue('greeting');
    // check the input
    $params['items'] = $form_state->getValue('greeting');
    // 2. Create a PrivateTempStore object with the collection 'greetingForm_values'.
    $tempstore = $this->tempStoreFactory->get('greetingForm_values');
    // 3. Store the $params array with the key 'params'.
    try {
      $tempstore->set('params', $params);
    } catch (\Exception $error) {
      // dump the error for now, read error, --fix this!

And the salutation function from the controller looks like this.

  public function salutation()
    $tempstore = $this->tempStoreFactory->get('greetingForm_values');
    $params = $tempstore->get('params'); // this value should come from the search form
    return [
      '#markup' => $this->salutation->getGreeting($params),

You're trying to do four things at once (form, service, integration with API, caching), so you can't see where the problem is. Instead, break this down into distinct steps.

First, code and debug your form. In the submit function, just use the messenger service in your form ($this->messenger()->addMessage('this is a test message');) to display a static value for your greeting. You should reach a point where visiting /hello and submitting the form will display the message. You can customize that message later. Get this working first.

Second, code and debug your service class. I find it useful to use drush php-script here to execute a standalone PHP script that accesses your service. That way you can ensure your service is doing exactly what you want, and figure out how to communicate with the external API, before you try to use your service in a form. You don't need the "_controller" in your routing file. The way to access your service is using \Drupal::service('hello_world.salutation')->salutation(). Instead of passing variables through a tempstore, pass them as parameters to your salutation() method. So your standalone PHP script for drush would look something like this:


  $greetings = \Drupal::service('hello_world.salutation')->salutation('some string entered on your form');
  echo $greetings;

Save this as test.php then execute this with drush php-script test.php.

Third, once your service is working as you want, integrate your service with your form. You should be able to take the PHP script you wrote in step two and insert it almost unchanged into your form submit function. (As a future enhancement, learn how to inject your service into the Form rather than use the static \Drupal::service() call, but that can wait until after you have this working).

Fourth (do this only after you have the above working), examine your need to cache data, and then implement some sort of caching in your service if needed. You haven't shown all your code or completely explained what you're doing, but I don't see anything that justifies using cache.nameofbin or a tempstore.


I would suggest taking a look at hook_form_alter

Forms can have multiple submit functions and its best not to wipe out the original functionality (unless that's what you really want to do)

Your code might look something like this

function yourmodule_YourFormID_form_alter(&$form, &$form_state) {
     // conditions you execute custom code

      $form['#submit'][] = 'yourmodule_submit_function';
  • This answer is not responsive to the question - the original poster was asked to create a custom form, not alter an existing form.
    – anonymous
    Dec 14 '20 at 0:53
  • The answer is the same regardless
    – sea26.2
    Dec 14 '20 at 16:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.