Search code examples
hhvmhacklangxhp

Get children of an XHPChild


I am trying to move my website to Hack and XHP, of course. Below is a structure of what code structure I want to achieve:

<ui:backstageHeader>
  <ui:backstageHeader-navItem href="/">stories</ui:backstageHeader-navItem>
  <ui:backstageHeader-navItem href="/story/send">send a story</ui:backstageHeader-navItem>
  <ui:backstageHeader-navItem href="/aboutus">support</ui:backstageHeader-navItem>
</ui:backstageHeader>

(Note: :ui:backstageHeader-navItem basically renders to <a href={$this->:href}>{$this->getCHildren}</a> so there is not need to attach its class here.)

Below is the code for :ui:backstageHeader:

final class :ui:backstageHeader extends :ui:base {
  attribute :div;
  children (:ui:backstageHeader-navItem)*;

  protected function compose() {
    $dom =
    <section class="backstage-header">
      <div class="container">
        <div class="cell-logo">
          <a href="/">
            <span class="no23-logo-white"></span>
          </a>
        </div>
        <div class="cell-navigation">
        </div>
        <div class="cell-account">
          <div class="cell-login">
            <div id="siteNav-login">Autentificare</div>
          </div>
        </div>
      </div>
    </section>;
    $mainContainer = $dom->getChildren("div")[0];
    $cellNavigation = $mainContainer->getChildren("div")[1];
    $navItems = <ul class="main-navigation"></ul>;
    foreach($this->getChildren() as $child) {
      $navItems->appendChild(<li>{$child}</li>);
    }
    $dom->appendChild($navItems);

    return $dom;
  }
}

I used the Terminal to debug my code using hhvm -m d <file.php>, and everything was alright there; however, when I get to my browser, I get 500 error header. This is what the log says:

Catchable fatal error: Hack type error: Could not find method getChildren in an object of type XHPChild at /var/www/res/ui/backstage-header.php line 25

The error comes from

$cellNavigation = $mainContainer->getChildren("div")[1];

But, somehow, I need to append ul.main-navigation to div.cell-navigation from my section.backstage-header.

How can I do it?


Solution

  • Don't structure your code this way. Built it up from the inside out, so that you don't have to do a ton of unreadable getChildren calls looking for specific children. Those calls are super hard to read, and super inflexible when you change the structure of your XHP. You wouldn't do something like node.firstChild.lastChild.lastChild.firstChild in the JS DOM, would you? No, there's a better way in JS, to find things by class or ID; in XHP, you can just build it up the right way in the first place!

    I'd give you an example of this, but it doesn't look like you actually use $mainContainer or $cellNavigation, so you can just remove those two problematic definitions.

    As an aside, you really shouldn't be getting your type errors as catchable fatals from HHVM; this is a last resort sort of check. Try running the hh_client checker directly, maybe even showing its result in your IDE; it will give you a much faster iteration cycle, and much more information than HHVM provides.