Sending form errors back to view via redirect

I recently started picking up on CakePHP and now I’m trying to build a contact form for my site.
It seems to work in validating the forms, but there’s something I want to do now.
I want it to show any errors that occur (like missing a required field).
However, I want it to show 2 different possible states:

  • A user error (user forgot a field or the field doesn’t meet the requirements), show this below the field (using Bootstrap 4)
  • A server error (mail couldn’t send from the server - for example, the SMTP server is down), shown using the Flash

I’ve been searching far and wide for this, but I couldn’t get any further on this without posting a question myself.
Below is all the code that I’m using (running CakePHP 3.6)

src/Template/Pages/contact.ctp (controlled by the PagesController):

<div class="container">
  <div class="row no-banner">
      <div class="col-md-6">
        <h4>Contact Form</h4>
        <div style="padding-bottom:25px;">
          Got a question? we'd love to hear it from you!<br />
          Send us a message and we'll respond as soon as possible!
        </div>
  
        <?= $this->Flash->render(); ?>

        <?= $this->Form->create("Contact",array("url"=>"/submit/contact","class"=>"contact-form","id"=>"contact-form")); ?>
        <?= $this->Form->control("name",array("placeholder"=>"Your Name","label"=>false,"class"=>"form-control")); ?>
        <?= $this->Form->control("email",array("placeholder"=>"Your Email","label"=>false,"class"=>"form-control")); ?>
        <?= $this->Form->control("subject",array("placeholder"=>"The Subject","label"=>false,"class"=>"form-control")); ?>
        <?= $this->Form->textarea("message",array("placeholder"=>"Your Message","label"=>false,"class"=>"form-control")); ?>
        <?= $this->Form->button('Submit',array("class"=>"btn")); ?>
        <?= $this->Form->end(); ?>
      </div>
      <div class="col-md-6">
        <h4>Social Media</h4>
        <div style="padding-bottom:25px;">
          We are active on a variety of of social media, feel free to like and follow us!
        </div>
        <a href="#"><i class="fab fa-facebook social-media-icon"></i></a>
        <a href="#"><i class="fab fa-discord social-media-icon"></i></a>
        <?= $this->Form->errors; ?>
      </div>
  </div>
</div>

src/Controller/ContactController.php:

<?php
  namespace App\Controller;

  use App\Controller\AppController;
  use App\Form\ContactForm;

  class ContactController extends AppController {
    public function add() {
      $contact = new ContactForm();
      if ($this->request->is('post')) {
        if ($contact->execute($this->request->getData())) {
          $this->Flash->success('We will get back to you asap!');
          $this->redirect($this->referer());
        } else {
          $this->Flash->error('There was an issue sending your mail. Please try again later!');
          $this->redirect($this->referer());
        }
      }
      $this->set('contact', $contact);
    }
  }

src/Form/ContactForm.php:

<?php
  namespace App\Controller;

  use App\Controller\AppController;
  use App\Form\ContactForm;

  class ContactController extends AppController {
    public function add() {
      $contact = new ContactForm();
      if ($this->request->is('post')) {
        if ($contact->execute($this->request->getData())) {
          $this->Flash->success('We will get back to you asap!');
          $this->redirect(array('controller' => 'Pages','action' => 'display','contact'));
        } else {
          $this->Flash->error('There was an issue sending your mail. Please try again later!');
          $this->redirect($this->referer());
        }
      }
      $this->set('contact', $contact);
    }
  }

For those wondering, yes, I also asked this on StackOverflow, but after a bit, I realized it might be easier to put it on the dedicated CakePHP forum <3

Two things you need to change.

First, don’t redirect on failure (Just continue). Second, the first argument of the Form->create() method should be the context of the form. In your case, it is the $contact instance of the form object (i.e. should be <?= $this->Form->create($contact.... With those changes in place, it’ll just work.

One other thing that I did notice, is that when you redirect in a controller action, you should return the redirect (i.e. return $this->redirect()). Otherwise the method will continue executing which may have a number of undesirable effects.

Also, the URL in the form should ideally be in the array form (i.e. ['controller' => 'Contacts', 'action' => 'add]) with a route declared as needed.

Ah yes I see.
I got it to work most of the way (and some extra with help from a friend).
I was holding on to the PagesController too much.
Also, thanks for the feedback on the URL builder, I forgot I could do that :slight_smile: