Form plugin returns null instead of a page via getPage()

From a plugin, I want to find the page associated with the forms found on modular subpages. This should work, as far as I understand:

public function onFormInitialized(Event $event) {
    $form = $event['form'];
    $page = $form->getPage();
    /* ... */
}

However, this leads to:

Return value of Grav\Plugin\Form\Form::getPage() must implement interface Grav\Common\Page\Interfaces\PageInterface, null returned

I was digging through the debugger as well as the documentation and source code, but can’t figure out why I’m seeing this error. Any hints appreciated.

@domsson, The following seems to be happening…

Form::getPage() should either return a page or null. However, Form::getPage() is being defined as returning a PageInterface and will therefor throw an Error if a null value is returned. It should probably be defined as returning a nullable value: ?PageInterface.

Why my example code fails in your test and succeeded in my test?

  1. If the page has not yet been cached (it’s new, or has been changed), onFormInitialized is handled before onPageInitialized.
    Form::getPage() should then return null, however, Grav decides to throw an error. I think this is a bug…

  2. If the page has been cached already, then event onFormInitialized is being handled after onPageInitialized.
    Form::getPage() will then correctly return the page.

That explains, I guess, why my test succeeded and yours fails. I probably did my test with an already cached page… I’ll update the previous post.

Alternative:

  • Add class variable $page and assign it in onPageInitialized.
  • In onFormInitialized check if $page has been set and use the value.

But isn’t onFormInitialized being called before onPageInitialized when page is not yet cached?
Yes… However, it seems that if the page has not yet been cached, onFormInitialized is called again after page is cached and onPageInitialized has been called.

Hope this helps…

1 Like

@domsson, I’ve Added an issue at the repo of the Form plugin. According the team, it is by design and won’t be fixed.

UPDATE: Team is considering how adding extra fields can be done safely.

There are two alternatives to work around this, both using the fact that onFormInitialized is called again after a page gets initialised.

Alternative 1:

  • Assign the page to class property $page during onPageInitialized
  • Use the class property in onFormInitialized

Alternative 2:

  • Use try-catch in onFormInitialized
    public function onFormInitialized(Event $event) {
      /** @var Form */
      $form = $event['form'];
    
      try {
          /** @var Page */
          $page = $form->getPage();
          // Add extra fields to form
      } catch (\TypeError $error) {
          // Handle or ignore
      }
    }
    

Note: The error thrown will change from \TypeError to LogicException in the near future. Keep an eye on the issue mentioned above.