When Drupal receives an incoming request the HTTP Kernel identifies the appropriate route for the requested path. The routing system then matches this route with a controller that has been registered to handle responses for these types of requests. Sections of code responsible for generating the response to these requests are called Controllers.
Example tasks
Write the code in a custom module that responds to particular incoming requests
Understand how to identify the controllers responsible for responding to a given url, path and route.
Confidence
Drupal's system of mapping request routes to controllers is quite well established. Since it's based on Symfony components it is unlikely to change dramatically in the foreseeable future.
Sometimes we need the response returned from a controller to be something other than HTML content wrapped with the rest of a Drupal theme. Maybe we need to return plain text, or JSON structured data for an application to consume. Perhaps we need greater control over the HTTP headers sent in the response. This is possible by building on the fact that controllers can return generic Response objects instead of renderable arrays, allowing you to gain complete control over what is sent to the requesting agent.
In this tutorial we'll:
Look at how to return a plain text response, and JSON data
Show how to make your responses cacheable by adding cacheability metadata
Learn about how to use a generic Symfony Response to gain greater control over what gets returned
By the end of this tutorial, you should be able to return responses from a controller in a Drupal module that are not HTML content wrapped in a Drupal theme.
Each form is defined by a controller, a class that implements the \Drupal\Core\Form\FormInterface. Form controllers declare the unique ID of the form, the $form array that describes the content of the form, how to validate the form, and what to do with the data collected.
In this tutorial we'll:
Define a new form controller class
Implement the required methods to describe a form
Add a route that can be used to access our form
By the end of this tutorial you should be able to define a form that adheres to the FormInterface requirements and know where to find more information about how to further customize your form controller.
When your module defines the form and the form controller, you can add your validation logic as part of the form controller. This is done via the implementation of a validateForm() method. The FormBuilder service will automatically invoke this method at the appropriate time during the process of submitting a form. While the validateForm() method is required by \Drupal\Core\Form\FormInterface, an empty method will fulfill that requirement. It's up to you to provide appropriate validation code inside the method.
In this tutorial we'll:
Use the validateForm() method of a form controller to verify user input
Demonstrate how to raise errors on a form element when it doesn't pass validation
By the end of this tutorial you should know how to validate your custom forms.
When you create a custom form for Drupal and your module defines the form controller, the best way to handle processing of submitted data is via the submitForm() method of your controller. This method is called automatically by the Form API during the process of handling a user-submitted form. It can be used to save incoming data to the database, trigger a workflow based on user input, and instruct the Form API where to send the user after form processing has completed.
In this tutorial we'll:
Demonstrate how to add a submitForm() method to a form controller class
Access the value(s) of form input elements via the $form_state object
Set a redirect after performing processing in a form submission handler
By the end of this tutorial you should know how to access the values of a submitted form, and how to write custom processing code inside of the submitForm() method of a form controller.
Eventually you'll want to do something with the information your form collects beyond just printing it to the screen. It's generally considered a best practice to keep business logic out of your form controller so that it can be reused. In order to accomplish that you'll generally define your business logic in a service, and then call out to that service from your form controller. Or, you can make use of one of the existing services provided by Drupal core to save data.
In this tutorial we'll:
Use dependency injection to inject a service into a form controller
Make use of a service injected into a form controller from within the buildForm() and submitForm() methods
By the end of this tutorial you'll understand how to inject one or more services into your form controller and then make use of them.
Note: As of Drupal 10.2, regular controllers can use AutowireTrait for automatic dependency injection. However, form controllers do not yet support autowiring and still require the manual create() method approach demonstrated in this tutorial. Learn more about autowiring in Create a Route and Controller.
The Examples project contains many sub-modules that demonstrate various Drupal sub-systems through well-documented code. To learn more about how routing and controllers work, take a look at the page_example module here.