I have a class with a signature:

class CRM_Contact_Form_Task_FooPdf extends CRM_Contact_Form_Task {

What generates a PDF. During the PDF generation, there might be an error. This task also uses the standard mail template:

public function buildQuickForm() {
  // Add message templates.
  CRM_Core_Resources::singleton()->addScriptFile('civicrm', 'templates/CRM/Contact/Form/Task/EmailCommon.js', 0, 'html-header');
  $this->addDefaultButtons(ts('Continue'), 'done', 'cancel');

It works totally fine. It shows up among the actions on a search form, when I select it, the template UI shows up, and i have access to the data. The only issue is that during the PDF generation, sometimes I need to raise an error, which is not a fatal error, but something that the user must correct himself. At the PDF generation, i am in the \CRM_Core_Form::postProcess() phase. Can I set a form error and re-display the form with the submitted values?

Issuing this (and of course skip to stream the PDF) does not work, as I am redirected simply to the main admin page of CiviCRM, the form is not re-generated:

$this->setElementError('text_message', 'moo');

But I guess it's because i am already at the postprocessing.

1 Answer 1


You are correct that postProcess runs too late. Consider the conventional request lifecycle for HTML_QuickForm/CRM_Core_Form:

Overall Request Lifecycle in CRM_Core_Form

At the end of the Validate phase, it makes a major decision about whether to rerender the form with errors. However, the postProcess function is part of the Process phase which should only run on valid forms.

The conventional way to set a validation error in HTML_QuickForm is to register a validation function. For example, in CRM_Group_Form_Edit::buildQuickForm(), note how it calls addFormRule(...) (and how the static function formRule() conditionally returns an array of errors). This runs at the correct time.

For mitigations, you might consider:

  • Add some checks in the validation phase to predict whether the error condition will arise. (Ex: If the issue is a missing dependency or inadequate RAM, then validate the dependency or RAM beforehand.)
  • Report the error via CRM_Core_Error::fatal(), throw new Exception(), or CRM_Core_Error::statusBounce().
  • Don't rely on HTML_QuickForm as the main form processor. Implement client-side logic with Javascript and AJAX callbacks.
  • (Evil but possibly working) Do the heavy lifting during the validate phase. (This will, e.g., make it hard for third-parties to hook into the form... but it may work...)
  • (Evil but possibly working) Dig into the mechanics of the CRM_Core_Form lifecycle and figure out a way to short-circuit/cross-wire the phases for your controller.
  • "Do the heavy lifting during the validate phase." - I will pick this approach, I'll generate the PDF at validation phase and serve it via HTTP at submission.
    – Aron Novak
    Aug 22, 2016 at 6:13

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.