Controllers

Overview of the routing configuration

Controller Development Guide for WebApp Package

Home documentation

This guide provides an overview of how to develop custom controllers for web applications using the WebApp package. By following this guide, developers can understand how to create and manage controllers, handle HTTP requests, validate data, and render responses.

Introduction

Controllers in the WebApp package are responsible for handling incoming HTTP requests, processing data, and returning responses. They play a central role in defining the business logic of the application and interacting with the web routes.

Example Controller

The example controller provided is the HomeController. It demonstrates various features such as handling forms, cookies, authentication, localization, and more. Below is a detailed breakdown of how this controller is structured and how developers can build their own controllers.

Controller Class Structure

The HomeController class extends WaController, which provides essential functionalities for handling web requests.

class HomeController extends WaController {
  HomeController(super.rq);

  @override
  Future<String> index() async {
    return renderTemplate('index');
  }
}
  • Constructor: HomeController(super.rq) initializes the controller with the WebRequest object.
  • index Method: This is the default method that renders the template for the home page.

Handling Forms

To handle forms, the controller uses FormValidator to validate form fields.

Future<String> exampleForm() async {
  if (rq.method == RequestMethods.POST) {
    var loginForm = FormValidator(
      name: 'loginForm',
      rq: rq,
      fields: {
        'email': [
          FieldValidator.isEmailField(),
          FieldValidator.requiredField(),
          FieldValidator.fieldLength(min: 5, max: 255)
        ],
        'password': [
          (value) {
            return FieldValidateResult(
              success: value.toString().isPassword,
              error: 'Password is not valid, it must have [Number/Char(Upper+Lower)/?@#\$!%]',
            );
          },
          FieldValidator.requiredField(),
          FieldValidator.fieldLength(min: 8, max: 255)
        ],
      },
    );

    var result = await loginForm.validateAndForm();
    var loginResult = false;

    if (result.result) {
      var email = rq.get<String>('email', def: '');
      var password = rq.get<String>('password', def: '');
      if (email == 'example@uproid.com' && password == '@Test123') {
        loginResult = true;
      }
    }

    rq.addParams({
      'loginForm': result.form,
      'loginResult': loginResult,
    });
  }

  return renderTemplate('example/form');
}
  • FormValidator: Validates form fields based on defined rules.
  • Handling POST Requests: Validates form data and processes login logic.

Handling Cookies

To manage cookies, you can use methods to add or remove cookies based on request parameters.

Future<String> exampleAddCookie() async {
  var name = rq.get<String>('name', def: '');
  var value = rq.get<String>('value', def: '');
  var safe = rq.get<bool>('safe', def: false);
  var action = rq.get<String>('action', def: 'add');

  if (action == 'delete') {
    rq.removeCookie(name);
  } else if (action == 'add' && name.isNotEmpty && value.isNotEmpty) {
    rq.addCookie(name, value, safe: safe);
  }

  return exampleCookie();
}
  • addCookie and removeCookie: Methods to manage cookies.

Rendering Templates

Templates can be rendered using the renderTemplate method, which helps in dynamically generating views.

Future<String> renderTemplate(String widget) async {
  MockUserModel? user;
  if (rq.session.containsKey('user')) {
    user = MockUserModel();
  }

  rq.addParams({
    'title': 'logo.title',
    'year': DateTime.now().year,
    'user': await user?.toParams(),
  });

  rq.addParam('widget', widget);
  return rq.renderView(path: "template/home");
}
  • renderTemplate: Adds parameters and renders a view.

Handling Errors

You can handle exceptions and errors by throwing exceptions in your controller methods.

Future<String> exampleError() async {
  throw Exception('This is an example error of exceptions');
}
  • throw: Raises exceptions to be handled globally or by middleware.

Sending Emails

The controller demonstrates how to send emails using the MailSender class.

Future<String> exampleEmailSend() async {
  var emailForm = FormValidator(
    name: 'emailForm',
    rq: rq,
    fields: {
      'email': [
        FieldValidator.requiredField(),
        FieldValidator.isEmailField(),
      ],
      'from': [
        FieldValidator.requiredField(),
        FieldValidator.isEmailField(),
      ],
      'subject': [
        FieldValidator.requiredField(),
        FieldValidator.fieldLength(min: 5, max: 255),
      ],
      'message': [
        FieldValidator.requiredField(),
        FieldValidator.fieldLength(min: 5, max: 1000),
      ],
      'host': [
        FieldValidator.requiredField(),
        FieldValidator.fieldLength(min: 5, max: 255),
      ],
      'port': [
        FieldValidator.isNumberField(
          min: 1,
          max: 65535,
          isRequired: true,
        ),
      ],
      'username': [
        FieldValidator.requiredField(),
        FieldValidator.fieldLength(min: 5, max: 255),
      ],
      'password': [
        FieldValidator.requiredField(),
        FieldValidator.fieldLength(min: 5, max: 255),
      ],
      'fromName': [
        FieldValidator.requiredField(),
        FieldValidator.fieldLength(min: 5, max: 255),
      ],
    },
  );

  var resEmailForm = await emailForm.validateAndForm();
  if (resEmailForm.result) {
    var resSendEmail = await MailSender.sendEmail(
      from: rq.get('from'),
      to: [rq.get('email')],
      subject: rq.get('subject'),
      text: rq.get('message'),
      html: rq.get('message'),
      host: rq.get('host'),
      port: rq.get('port', def: 465),
      username: rq.get('username'),
      password: rq.get('password'),
      ssl: rq.get('ssl', def: true),
      allowInsecure: rq.get('allowInsecure', def: true),
      fromName: rq.get('fromName'),
    );

    if (resSendEmail) {
      rq.addParam('sendEmailSuccess', 'Email sent successfully');
    } else {
      rq.addParam('sendEmailFailed', 'Email not sent');
    }
  }

  rq.addParams({
    'emailForm': resEmailForm.form,
  });

  return renderTemplate('example/email');
}
  • MailSender.sendEmail: Sends an email based on form data.

Developing Your Own Controllers

To create your own controllers:

  1. Extend WaController: Define your controller class by extending WaController.
  2. Define Methods: Implement methods to handle various routes and actions.
  3. Use FormValidator: Validate form input as needed.
  4. Render Templates: Use renderTemplate to generate HTML responses.
  5. Handle Cookies and Sessions: Manage cookies and session data with provided methods.
  6. Manage Errors: Implement error handling to capture and respond to exceptions.
  7. Send Emails: Utilize the MailSender for email functionality if required.

By following these guidelines and using the provided example, you can effectively develop and customize controllers for your web applications using the WebApp package.