Provide data from API across different nodes

Hello,

We are currently working on a way to create and send newsletters with Neos. The content mainly consists of teaser nodes which fetch their data from an API (title, topline, url, abstract and image). Those teaser nodes can be articles, downloads or webinars for example. The user also has an option to insert a table of contents in the newsletter which fetches the topline and title from all currently placed teasers and shows them in a simple <li> list.

To fill a teaser the user has a search field in the inspector to select content from our database. The ID of the selected content is then saved on the node to access the API from within Fusion and retrieve the data to display.

The problem is that the table of contents node needs the title and topline on the teaser node to access and display it. In order to achieve this, we write the properties back to the teaser node within Fusion after accessing the API. From an architectural point of view we don’t want to do write operations in Fusion, but we currently don’t have any idea on how we can provide the title and topline for the table of contents otherwise.

Are there any other, smarter ways to solve this?

prototype(Vcg.Newsletter:Content.Artikelteaser) < prototype(Neos.Neos:ContentComponent) {
  @context.teaser = ${teaserH.fetchTeaserData(node)}

  url = ${teaser.url}
  title = ${teaser.title}
  topline = ${teaser.topline}
  abstract = ${teaser.abstract}

  node = ${teaserH.writeNodeProperties(node, this.topline, this.title, this.url)}

  image_attributes = Neos.Fusion:DataStructure {
      style = "display:block; border:none; outline:none; text-decoration:none;"
      border = 0
      width = 300
    }
  
    image_source = Sitegeist.Kaleidoscope:UriImageSource {
      uri = ${nlImageH.getImageUrl(teaser.image, 300, 300, true, null, "jpg", 80, true)}
    }

  @context.content_id = ${q(node).property('content_id')}
  renderer = Neos.Fusion:Case {
    # wird geladen, wenn Content ausgewaehlt wurde
    contentAusgewaehlt {
      condition = ${content_id != ''}
      renderer =  Vcg.Newsletter:Component.Molecule.Teaser {
        @apply.props = ${props}
      }
    }
    # wird geladen, wenn kein Content ausgewaehlt wurde
    default {
      condition = ${node.context.inBackend}
      renderer = Vcg.Nodetypes:Component.Atom.BackendHinweisBox {
        element_name = "Artikel Teaser"
      }
    }
  }
}
public function writeNodeProperties(NodeInterface $node, string $topline, string $title, string $url): NodeInterface
    {
        if ($node->getProperty('content_id') === '' || $node->getProperty('application') === '') {
            return $node;
        }

        $node->setProperty('topline', $topline);
        $node->setProperty('title', $title);
        $node->setProperty('url', $url);
        $this->persistence_manager->persistAll();

        return $node;
    }

Why would it need those as node properties? it could render them just as the teasers themselves do it, by accessing the API based on the ID in the node. Or am I missing something?

I think that is way more promising and then add a cache layer in the API calls maybe if it’s a performance problem.

1 Like

Oh if you want (not sure that is really necessary with AFX and components these days) to retain the option to use q(node).properties(‘topline’) for example, you might want to look into custom node implementations and override the getProperty() method to access the API instead for those properties. We will probably drop it in Neos 9 with the new ContentRepository though.

1 Like

Hi Christan,

Thanks for the reply!

The problem is that we need to fetch different properties from the API depending on the NodeType. One type needs the property ‘url’ and another type needs ‘link’ instead etc. We wanted to keep it simple and universal instead of having lots of If-Statements per NodeType.

We were able to solve the problem with a singleton class named TableOfContentsDatastore. Each node uses an EelHelper to write its values (title, topline, url, abstract and image) into the TableOfContentsDatastore. The node TableOfContents dynamically fetches the values from the datastore when rendering the toplevel at the end.