Utilities for the Contentful Rich Text

Overview

rich-text.php

Packagist PHP minimum version CircleCI License

This library is built to help you with the parsing and rendering of the rich text field type in Contentful. It requires PHP 7.2 and up or PHP 8.0 and up.

Setup

Add this package to your application by using Composer and executing the following command:

composer require contentful/rich-text

Then, if you haven't already, include the Composer autoloader:

require_once 'vendor/autoload.php';

Parsing

The method Contentful\RichText\Parser::parse(array $data) accepts a valid, unserialized rich text data structure, and returns an object which implements Contentful\RichText\Node\NodeInterface.

$parser = new Contentful\RichText\Parser();

// Fetch some data from an entry field from Contentful

/** @var Contentful\RichText\Node\NodeInterface $node */
$node = $parser->parse($data);

Depending of which type of node it actually is, the hierarchy can be navigated using getter methods. Please refer to the full list of available nodes for a complete reference.

Rendering

The main purpose of this library is to provide an automated way of rendering nodes. The simplest setup involves just creating an instance of the Contentful\RichText\Renderer class:

$renderer = new Contentful\RichText\Renderer();

$output = $renderer->render($node);

The library provides defaults for all types of supported nodes. However, it is likely that you will need to override some of these defaults, in order to customize the output. To do this, you will create NodeRenderer classes, which implement the Contentful\RichText\NodeRenderer\NodeRendererInterface interface:

namespace Contentful\RichText\NodeRenderer;

use Contentful\RichText\Node\NodeInterface;
use Contentful\RichText\RendererInterface;

/**
 * NodeRendererInterface.
 *
 * A class implementing this interface is responsible for
 * turning a limited subset of objects implementing NodeInterface
 * into a string.
 *
 * The node renderer makes the support for a certain node explicit by
 * implementing the "supports" method.
 *
 * The node renderer can also throw an exception during rendering if
 * the given node is not supported.
 */
interface NodeRendererInterface
{
    /**
     * Returns whether the current renderer
     * supports rendering the given node.
     *
     * @param NodeInterface $node The node which will be tested
     *
     * @return bool
     */
    public function supports(NodeInterface $node): bool;

    /**
     * Renders a node into a string.
     *
     * @param RendererInterface $renderer The generic renderer object, which is used for
     *                                    delegating rendering of nested nodes (such as ListItem in lists)
     * @param NodeInterface     $node     The node which must be rendered
     * @param array             $context  Optionally, extra context variables (useful with custom node renderers)
     *
     * @throws \InvalidArgumentException when the given $node is not supported
     *
     * @return string
     */
    public function render(RendererInterface $renderer, NodeInterface $node, array $context = []): string;
}

For instance, if you want to add a class to all h1 tags, you will have something similar to this:

use Contentful\RichText\NodeRenderer\NodeRendererInterface;
use Contentful\RichText\Node\NodeInterface;
use Contentful\RichText\Node\Heading1;
use Contentful\RichText\RendererInterface;

class CustomHeading1 implements NodeRendererInterface
{
    public function supports(NodeInterface $node): bool
    {
        return $node instanceof Heading1;
    }

    public function render(RendererInterface $renderer, NodeInterface $node, array $context = []): string
    {
        return '<h1 class="my-custom-class">'.$renderer->renderCollection($node->getContent()).'</h1>';
    }
}

Finally, you will need to tell the main renderer to use your custom node renderer:

$renderer->pushNodeRenderer(new CustomHeading1());

Now all instances of Heading1 node will be rendered using the custom node renderer. You can implement any sort of logic in the supports method, and since only an interface is required, you can inject any sort of dependency in the constructor. This is done, for instance, for allowing the use of templating engines such as Twig or Plates:

use Twig\Environment;
use Contentful\RichText\NodeRenderer\NodeRendererInterface;
use Contentful\RichText\Node\NodeInterface;
use Contentful\RichText\Node\Heading1;
use Contentful\RichText\RendererInterface;

class TwigCustomHeading1 implements NodeRendererInterface
{
    /**
     * @var Environment
     */
    private $twig;

    public function __construct(Environment $twig)
    {
        $this->twig = $twig;
    }

    public function supports(NodeInterface $node): bool
    {
        return $node instanceof Heading1;
    }

    public function render(RendererInterface $renderer, NodeInterface $node, array $context = []): string
    {
        $context['node'] = $node;

        return $this->twig->render('heading1.html.twig', $context);
    }
}

This library provides out-of-the-box support for Twig and Plates, which allow you to call RenderInterface::render() and RenderInterface::renderCollection() methods from a template. To enable the appropriate extension, just let the Twig environment or Plates engine know about it as described below.

Twig integration

Setup:

$renderer = new Contentful\RichText\Renderer();

// Register the Twig extension, which will provide functions
// rich_text_render() and rich_text_render_collection()
// in a Twig template
$extension = new Contentful\RichText\Bridge\TwigExtension($renderer);

/** @var Twig\Environment $twig */
$twig->addExtension($extension);

// Finally, tell the main renderer about your custom node renderer
$customTwigHeading1NodeRenderer = new TwigCustomHeading1($twig);
$renderer->pushNodeRenderer($customTwigHeading1NodeRenderer);

Template:

<h1 class="my-custom-class">{{ rich_text_render_collection(node.content) }}</h1>  

For an example implementation of a Twig-based rendering process, check the test node renderer and the complete integration test.

Plates integration

Setup:

$renderer = new \Contentful\RichText\Renderer();

// Register the Plates extension, which will provide functions
// $this->richTextRender() and $this->richTextRenderCollection()
// in a Plates template
$extension = new \Contentful\RichText\Bridge\PlatesExtension($renderer);

/** @var League\Plates\Engine $plates */
$plates->loadExtension($extension);

// Finally, tell the main renderer about your custom node renderer
$customPlatesHeading1NodeRenderer = new PlatesCustomHeading1($plates);
$renderer->pushNodeRenderer($customPlatesHeading1NodeRenderer);

Template:

// The function will output HTML, so remember *not* to escape it using $this->e()
<?= $this->richTextRenderCollection($node->getContent()) ?>

For an example implementation of a Plates-based rendering process, check the test node renderer and the complete integration test.

How to avoid having the main renderer throw an exception on unknown nodes

The default renderer behavior for when it does not find an appropriate node renderer is to throw an exception. To avoid this, you must set it up to use a special catch-all node renderer:

$renderer = new Contentful\RichText\Renderer();
$renderer->appendNodeRenderer(new Contentful\RichText\NodeRenderer\CatchAll());

The special Contentful\RichText\NodeRenderer\CatchAll node renderer will return an empty string regardless of the node type. It's important to use the appendNodeRenderer instead of the usual pushNodeRenderer method to make this special node renderer have the lowest priority, therefore avoiding it intercepting regular node renderers.

Glossary

Name Interface Description
Node Contentful\RichText\Node\NodeInterface The PHP representation of a rich text node
Renderer Contentful\RichText\RendererInterface A class which accepts all sorts of nodes, and then delegates rendering to the appropriate node renderer
Node renderer Contentful\RichText\NodeRenderer\NodeRendererInterface A class whose purpose is to be able to render a specific type of node
Parser Contentful\RichText\ParserInterface A class that's responsible for turning an array of unserialized JSON data into a tree of node objects

About Contentful

Contentful is a content management platform for web applications, mobile apps and connected devices. It allows you to create, edit & manage content in the cloud and publish it anywhere via powerful API. Contentful offers tools for managing editorial teams and enabling cooperation between organizations.

License

Copyright (c) 2015-2019 Contentful GmbH. Code released under the MIT license. See LICENSE for further details.

Comments
  • Two objects referencing each other with Rich Text field cause infinite recursion

    Two objects referencing each other with Rich Text field cause infinite recursion

    See https://github.com/contentful/contentful.php/issues/278

    So I've set up this demo space (spaceId=49rugrz7ojq7) to demonstrate the problem.

    The very minimal setup is:

    1. One content type (page) with a rich-text field.
    2. Two entries for the above content type having a hyperlink reference to another one via their rich-text content body.

    When you try to fetch one of them -- Contetnful delivery client falls into infinite recursion of resolving links.

    • On production, it runs forever until it uses all available memory. And then fails.
    • Also, this was a nightmare to debug, as the problem is not happening in development environments with xdebug installed. This is because xdebug has xdebug.max_nesting_level set to 256 by default. So it just stops thanks to EntryHyperlink silently converting any error into MapperExceptions (see #44), which is then caught to return an instance of \Contentful\RichText\Node\Nothing.

    https://github.com/contentful/rich-text.php/blob/42a72fa45a1a04b28b45d173b153518f530e7cd6/src/NodeMapper/EntryHyperlink.php#L31-L38

    Example stack trace
    #0 /website/vendor/guzzlehttp/psr7/src/MessageTrait.php(188): array_map(Object(Closure), Array)
    #1 /website/vendor/guzzlehttp/psr7/src/MessageTrait.php(169): GuzzleHttp\Psr7\Response->trimHeaderValues(Array)
    #2 /website/vendor/guzzlehttp/psr7/src/MessageTrait.php(147): GuzzleHttp\Psr7\Response->normalizeHeaderValue(Array)
    #3 /website/vendor/guzzlehttp/psr7/src/Response.php(106): GuzzleHttp\Psr7\Response->setHeaders(Array)
    #4 /website/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php(81): GuzzleHttp\Psr7\Response->__construct(200, Array, Object(GuzzleHttp\Psr7\Stream), '1.1', 'OK')
    #5 /website/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(545): GuzzleHttp\Handler\EasyHandle->createResponse()
    #6 [internal function]: GuzzleHttp\Handler\CurlFactory->GuzzleHttp\Handler\{closure}(Resource id #7, '\r\n')
    #7 /website/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php(40): curl_exec(Resource id #7)
    #8 /website/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php(28): GuzzleHttp\Handler\CurlHandler->__invoke(Object(GuzzleHttp\Psr7\Request), Array)
    #9 /website/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php(51): GuzzleHttp\Handler\Proxy::GuzzleHttp\Handler\{closure}(Object(GuzzleHttp\Psr7\Request), Array)
    #10 /website/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php(37): GuzzleHttp\Handler\Proxy::GuzzleHttp\Handler\{closure}(Object(GuzzleHttp\Psr7\Request), Array)
    #11 /website/vendor/guzzlehttp/guzzle/src/Middleware.php(30): GuzzleHttp\PrepareBodyMiddleware->__invoke(Object(GuzzleHttp\Psr7\Request), Array)
    #12 /website/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php(70): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Request), Array)
    #13 /website/vendor/guzzlehttp/guzzle/src/Middleware.php(60): GuzzleHttp\RedirectMiddleware->__invoke(Object(GuzzleHttp\Psr7\Request), Array)
    #14 /website/vendor/guzzlehttp/guzzle/src/HandlerStack.php(67): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Request), Array)
    #15 /website/vendor/guzzlehttp/guzzle/src/Client.php(277): GuzzleHttp\HandlerStack->__invoke(Object(GuzzleHttp\Psr7\Request), Array)
    #16 /website/vendor/guzzlehttp/guzzle/src/Client.php(98): GuzzleHttp\Client->transfer(Object(GuzzleHttp\Psr7\Request), Array)
    #17 /website/vendor/guzzlehttp/guzzle/src/Client.php(106): GuzzleHttp\Client->sendAsync(Object(GuzzleHttp\Psr7\Request), Array)
    #18 /website/vendor/contentful/core/src/Api/Requester.php(64): GuzzleHttp\Client->send(Object(GuzzleHttp\Psr7\Request))
    #19 /website/vendor/contentful/core/src/Api/BaseClient.php(110): Contentful\Core\Api\Requester->sendRequest(Object(GuzzleHttp\Psr7\Request))
    #20 /website/vendor/contentful/contentful/src/Client.php(510): Contentful\Core\Api\BaseClient->callApi('GET', '/spaces/49rugrz...', Array)
    #21 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #22 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '4q2NQEDu1shvLuE...', 'en-US')
    #23 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('4q2NQEDu1shvLuE...', NULL)
    #24 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #25 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #26 [internal function]: Contentful\RichText\Parser->parse(Array)
    #27 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #28 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #29 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #30 [internal function]: Contentful\RichText\Parser->parse(Array)
    #31 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #32 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #33 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #34 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #35 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #36 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #37 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #38 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #39 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #40 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #41 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '2nhxBnMkN5zyKwG...', 'en-US')
    #42 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('2nhxBnMkN5zyKwG...', NULL)
    #43 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #44 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #45 [internal function]: Contentful\RichText\Parser->parse(Array)
    #46 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #47 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #48 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #49 [internal function]: Contentful\RichText\Parser->parse(Array)
    #50 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #51 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #52 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #53 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #54 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #55 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #56 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #57 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #58 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #59 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #60 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '4q2NQEDu1shvLuE...', 'en-US')
    #61 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('4q2NQEDu1shvLuE...', NULL)
    #62 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #63 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #64 [internal function]: Contentful\RichText\Parser->parse(Array)
    #65 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #66 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #67 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #68 [internal function]: Contentful\RichText\Parser->parse(Array)
    #69 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #70 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #71 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #72 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #73 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #74 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #75 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #76 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #77 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #78 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #79 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '2nhxBnMkN5zyKwG...', 'en-US')
    #80 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('2nhxBnMkN5zyKwG...', NULL)
    #81 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #82 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #83 [internal function]: Contentful\RichText\Parser->parse(Array)
    #84 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #85 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #86 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #87 [internal function]: Contentful\RichText\Parser->parse(Array)
    #88 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #89 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #90 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #91 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #92 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #93 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #94 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #95 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #96 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #97 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #98 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '4q2NQEDu1shvLuE...', 'en-US')
    #99 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('4q2NQEDu1shvLuE...', NULL)
    #100 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #101 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #102 [internal function]: Contentful\RichText\Parser->parse(Array)
    #103 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #104 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #105 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #106 [internal function]: Contentful\RichText\Parser->parse(Array)
    #107 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #108 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #109 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #110 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #111 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #112 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #113 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #114 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #115 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #116 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #117 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '2nhxBnMkN5zyKwG...', 'en-US')
    #118 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('2nhxBnMkN5zyKwG...', NULL)
    #119 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #120 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #121 [internal function]: Contentful\RichText\Parser->parse(Array)
    #122 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #123 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #124 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #125 [internal function]: Contentful\RichText\Parser->parse(Array)
    #126 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #127 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #128 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #129 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #130 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #131 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #132 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #133 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #134 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #135 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #136 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '4q2NQEDu1shvLuE...', 'en-US')
    #137 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('4q2NQEDu1shvLuE...', NULL)
    #138 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #139 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #140 [internal function]: Contentful\RichText\Parser->parse(Array)
    #141 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #142 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #143 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #144 [internal function]: Contentful\RichText\Parser->parse(Array)
    #145 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #146 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #147 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #148 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #149 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #150 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #151 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #152 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #153 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #154 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #155 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '2nhxBnMkN5zyKwG...', 'en-US')
    #156 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('2nhxBnMkN5zyKwG...', NULL)
    #157 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #158 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #159 [internal function]: Contentful\RichText\Parser->parse(Array)
    #160 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #161 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #162 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #163 [internal function]: Contentful\RichText\Parser->parse(Array)
    #164 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #165 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #166 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #167 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #168 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #169 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #170 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #171 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #172 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #173 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #174 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '4q2NQEDu1shvLuE...', 'en-US')
    #175 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('4q2NQEDu1shvLuE...', NULL)
    #176 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #177 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #178 [internal function]: Contentful\RichText\Parser->parse(Array)
    #179 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #180 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #181 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #182 [internal function]: Contentful\RichText\Parser->parse(Array)
    #183 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #184 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #185 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #186 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #187 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #188 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #189 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #190 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #191 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #192 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #193 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '2nhxBnMkN5zyKwG...', 'en-US')
    #194 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('2nhxBnMkN5zyKwG...', NULL)
    #195 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #196 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #197 [internal function]: Contentful\RichText\Parser->parse(Array)
    #198 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #199 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #200 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #201 [internal function]: Contentful\RichText\Parser->parse(Array)
    #202 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #203 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #204 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #205 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #206 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #207 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #208 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #209 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #210 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #211 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #212 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '4q2NQEDu1shvLuE...', 'en-US')
    #213 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('4q2NQEDu1shvLuE...', NULL)
    #214 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #215 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #216 [internal function]: Contentful\RichText\Parser->parse(Array)
    #217 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #218 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #219 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #220 [internal function]: Contentful\RichText\Parser->parse(Array)
    #221 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #222 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #223 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #224 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #225 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #226 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #227 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #228 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #229 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #230 /website/vendor/contentful/contentful/src/Client.php(541): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #231 /website/vendor/contentful/contentful/src/Client.php(362): Contentful\Delivery\Client->requestWithCache('/spaces/49rugrz...', Array, 'Entry', '2nhxBnMkN5zyKwG...', 'en-US')
    #232 /website/vendor/contentful/contentful/src/LinkResolver.php(57): Contentful\Delivery\Client->getEntry('2nhxBnMkN5zyKwG...', NULL)
    #233 /website/vendor/contentful/rich-text/src/NodeMapper/EntryHyperlink.php(34): Contentful\Delivery\LinkResolver->resolveLink(Object(Contentful\Core\Api\Link))
    #234 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\EntryHyperlink->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #235 [internal function]: Contentful\RichText\Parser->parse(Array)
    #236 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #237 /website/vendor/contentful/rich-text/src/NodeMapper/Paragraph.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #238 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Paragraph->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #239 [internal function]: Contentful\RichText\Parser->parse(Array)
    #240 /website/vendor/contentful/rich-text/src/Parser.php(84): array_map(Array, Array)
    #241 /website/vendor/contentful/rich-text/src/NodeMapper/Document.php(26): Contentful\RichText\Parser->parseCollection(Array)
    #242 /website/vendor/contentful/rich-text/src/Parser.php(67): Contentful\RichText\NodeMapper\Document->map(Object(Contentful\RichText\Parser), Object(Contentful\Delivery\LinkResolver), Array)
    #243 /website/vendor/contentful/contentful/src/Mapper/Entry.php(180): Contentful\RichText\Parser->parse(Array)
    #244 /website/vendor/contentful/contentful/src/Mapper/Entry.php(104): Contentful\Delivery\Mapper\Entry->formatValue('RichText', Array, NULL)
    #245 /website/vendor/contentful/contentful/src/Mapper/Entry.php(57): Contentful\Delivery\Mapper\Entry->buildFields(Object(Contentful\Delivery\Resource\ContentType), Array, NULL)
    #246 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\Entry->map(NULL, Array)
    #247 /website/vendor/contentful/contentful/src/ResourceBuilder.php(150): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array, NULL)
    #248 /website/vendor/contentful/contentful/src/Mapper/ResourceArray.php(31): Contentful\Delivery\ResourceBuilder->build(Array)
    #249 [internal function]: Contentful\Delivery\Mapper\ResourceArray->Contentful\Delivery\Mapper\{closure}(Array)
    #250 /website/vendor/contentful/contentful/src/Mapper/ResourceArray.php(32): array_map(Object(Closure), Array)
    #251 /website/vendor/contentful/core/src/ResourceBuilder/BaseResourceBuilder.php(61): Contentful\Delivery\Mapper\ResourceArray->map(NULL, Array)
    #252 /website/vendor/contentful/contentful/src/ResourceBuilder.php(126): Contentful\Core\ResourceBuilder\BaseResourceBuilder->build(Array)
    #253 /website/vendor/contentful/contentful/src/Client.php(518): Contentful\Delivery\ResourceBuilder->build(Array)
    #254 /website/vendor/contentful/contentful/src/Client.php(382): Contentful\Delivery\Client->request('GET', '/spaces/49rugrz...', Array)
    #255 /website/web/index.php(19): Contentful\Delivery\Client->getEntries(Object(Contentful\Delivery\Query))
    #256 {main}
    
    
    opened by e1himself 12
  • Possible memory leak in the parser

    Possible memory leak in the parser

    Hi,

    I am trying to render a rich text field in my Symfony app. The field really doesn't have much data, just a heading, embedded entry and embedded asset.

    When I execute: $parser->parse($field);

    It hits the memory limit of 4G, which is way too much :)

    $parser is the Contentful\RichText\Parser $field is the array returned by the dynamic func: Entry->getFieldIdentifier()

    Any ideas?

    opened by ilukac 9
  • Entry references mappers are hiding bugs

    Entry references mappers are hiding bugs

    This catch-all exception inside EntryHyperlink and other mappers implementation is hiding any error occurring during the link resolution.

    Which may hide dangerous bugs and makes it nearly impossible to debug problems (see https://github.com/contentful/rich-text.php/issues/43).

    https://github.com/prezly-forks/contentful-rich-text.php/blob/6ac52e25334ab9a43e08c849149c2f91ead66616/src/NodeMapper/EntryHyperlink.php#L31-L38

    try {
        /** @var EntryInterface $entry */
        $entry = $linkResolver->resolveLink(
            new Link($linkData['id'], $linkData['linkType'])
        );
    } catch (\Throwable $exception) {
        throw new MapperException($data);
    }
    
    opened by e1himself 4
  • How to render an image embedded in a Rich Text field?

    How to render an image embedded in a Rich Text field?

    I'm currently grabbing the asset url as such, yet I'm getting a warning that getAsset() does not exists on NodeInterface.

    public function render(RendererInterface $renderer, NodeInterface $node, array $context = []): string
    {
        $url = $node->getAsset()->getFile()->getUrl();
        return '<img src=' . $url . ' />';
    }
    
    opened by jellevandevelde 3
  • allow php8

    allow php8

    i'm going to create a series of pr all over related packages to https://github.com/contentful/contentful-laravel

    prs:

    • https://github.com/contentful/contentful-core.php/pull/44
    • https://github.com/contentful/contentful-laravel/pull/40
    • https://github.com/contentful/rich-text.php/pull/56
    • https://github.com/contentful/contentful.php/pull/296
    opened by marvinosswald 3
  • Too few arguments to Parser

    Too few arguments to Parser

    Hello, I caught an error when calling parser and renderer for RichText

    2019/03/19 06:21:17 [error] 6#6: *5 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught ArgumentCountError: Too few arguments to function Contentful\RichText\Parser::__construct(), 0 passed in /var/www/html/include/contentful_function.php on line 82 and at least 1 expected in /var/www/html/assets/vendor/contentful/rich-text/src/Parser.php:45
    

    My code is:

    ...
        $parser = new Contentful\RichText\Parser();
        $renderer = new Contentful\RichText\Renderer();
        
        $node = $parser->parse($data);
    ...
    

    What parameter do I have to put on Parser constructor?

    Thanks.

    opened by kination 3
  • table-header-cell not support in the latest version

    table-header-cell not support in the latest version

    When adding a new table element on the richtext,

    If I enable table header, the code throw out the following errors.

    Unrecognized node type "table-header-cell" when trying to parse rich text.

    Works when disable the header cell image

    opened by brightq 2
  • LinkResolverInterface

    LinkResolverInterface

    Hello,

    I am confused with what the LinkResolverInterface argument should be. I am following the example in https://github.com/contentful/rich-text.php#parsing

    Screenshot 2021-05-26 at 12 59 57

    Trying to parse multiple nodeType: paragraph which returns a Contentful\RichText\Node\Document

    opened by Raymond-Ly 2
  • [Question] using rich-text.php with PHP5.6

    [Question] using rich-text.php with PHP5.6

    Hello,

    We are working on old code base using codeigniter2 and PHP5.6, no composer, I just want to retrieve the modules as HTML, I did not find old version of this package, the current API return a lot of nodes that I cannot parse to HTML.

    Any suggestion ?

    opened by kossa 2
  • Rich Text parse Linked Resource without locale specification

    Rich Text parse Linked Resource without locale specification

    Steps to reproduce

    1. Create a Contentful Space with 2 locales: English (default) and Italian;
    2. Create an Entry Model "Blog Post" with a Body field of type Rich Text;
    3. Create a "Blog Post" Entry with an Image in the Body field, the same image for the English and Italian Body fields;
    4. The Image Asset has both title and description filled in both languages;
    5. Try to render the Blog Post Entry in the not default language (Italian)

    Expected Result

    The title of the image present in the Body of the Blog Post should be in Italian

    Actual Result

    The title of the image present in the Body of the Blog Post is in English

    Considerations

    The issue is in the use of the \Contentful\Core\Api\LinkResolverInterface Interface. The Mappers should pass also the locale code in the second argument $parameters. The Mappers that use this interface are:

    1. \Contentful\RichText\NodeMapper\AssetHyperlink
    2. \Contentful\RichText\NodeMapper\EmbeddedAssetBlock
    3. \Contentful\RichText\NodeMapper\EmbeddedAssetInline
    4. \Contentful\RichText\NodeMapper\Reference\EntryReference
    opened by lamasfoker 1
  • EmbeddedAssetBlock JSON doesn't contain asset

    EmbeddedAssetBlock JSON doesn't contain asset

    The jsonSerialize method on the class Contentful\RichText\Node\EmbeddedAssetBlock looks like this:

    /**
     * {@inheritdoc}
     */
    public function jsonSerialize(): array
    {
        return [
            'nodeType' => self::getType(),
            'data' => [
                'target' => $this->asset->asLink(),
            ],
            'content' => $this->content
        ];
    }
    

    The content is empty, but it would be a lot more useful if $this->asset was returned instead. From that, I could access the file's url and other useful meta information

    Would you like me to raise a pull request?

    opened by twhite94 1
  • link resolver.

    link resolver.

    Hello

    I'm trying the get some nice html from the json i get from the graphql api using php. But i keep stuck with the "You will also need a link resolver to instanciate the parser." I have absolutely no idea how to get it. I there a way to have a full working example from the call to the render? Is what i'm trying even correct?

    opened by davouid 1
  • Can't create an Entry with RichText-Field

    Can't create an Entry with RichText-Field

    I'm trying to create an new Entry with a RichText field like this:

    `$text1 = new Text('TEXT1 '); $text2 = new Text('TEXT 2');

        $paragraph = new Paragraph([$text1, $text2]);
        $document = new Document([$paragraph]);
    
        $entry = new Entry('test');
        $entry->setField(
            'body',
            'en-US',
            $document,
        );
    
        $environmentProxy->create($entry);`
    

    When i run this, i'll get following Error from the Contentful API:

    {
      "sys": {
        "type": "Error",
        "id": "InvalidEntry"
      },
      "message": "Validation error",
      "details": {
        "errors": [
          {
            "name": "required",
            "details": "The property \"data\" is required here",
            "path": [
              "fields",
              "body",
              "zzz-AA",
              "data"
            ]
          }
        ]
      }
    }
    

    Whats the Problem here? I hope somebody can help me here.

    opened by LrMiLoef 3
Releases(v4.0.1)
  • v4.0.1(Dec 22, 2022)

  • 4.0.0(Dec 22, 2022)

    Changed

    • Breaking change: Added locale support to the richtext parser. This avoids bugs when parsing embedded fields using a different locale (see #65). This change changes the ParserInterface and NodeMapperInterface - any implementation using a custom parser or NodeMapper will need to update the entries accordingly. Additionally, the ParserInterface::parse() and ParserInterface::parseCollection() methods have been deprecated in favor of their localized version (ParserInterface::parseLocalized() and ParserInterface::parseCollectionLocalized(), respectively).
    • Breaking change: Dropped support for PHP7.
    • Added the embedded asset to the serialized version of EmbeddedAssetBlock and EmbeddedAssetInline (see #61).
    • Added support for superscript and subscript.

    Internal

    • Overall CI cleanup
    • Added CI tests for PHP8.2
    Source code(tar.gz)
    Source code(zip)
  • 3.4.0(Jul 17, 2022)

  • 3.3.0(Apr 25, 2022)

  • 3.2.0(Mar 25, 2021)

  • 3.1.2(Sep 10, 2020)

  • 3.1.1(Aug 20, 2020)

  • 3.1.0(Apr 8, 2020)

  • 3.0.0(Mar 3, 2020)

  • 2.0.0(Feb 19, 2020)

    Changed

    • Nested references are not fetched recursively upfront, they are now resolved dynamically when used
    • Changed parameters/signatures for EmbeddedEntryBlock, EmbeddedEntryInline, EntryHyperlink,
    • Added EntryReferenceInterface and implementation
    • MapperException not thrown anymore
    Source code(tar.gz)
    Source code(zip)
  • 1.2.1(Nov 26, 2019)

  • 1.2.0(Oct 31, 2018)

  • 1.1.1(Oct 30, 2018)

  • 1.1.0(Oct 30, 2018)

    Added

    • Method Parser::setNodeMapper(string $nodeType, NodeMapperInterface $nodeMapper) was added, now it's possible to define custom mappers after the parser's creation.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Oct 25, 2018)

    Added

    • Node Nothing has been implemented, which is used as a replacement for when creating other nodes does not succeed (e.g. a link can't be resolved).
    • Node EmbeddedAssetBlock has been implemented.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0-beta5(Oct 16, 2018)

    Changed

    • Node AssetHyperlink now expects an object implementing AssetInterface instead of ResourceInterface. [BREAKING]
    • Nodes EmbeddedEntryBlock and EntryHyperlink now expects an object implementing EntryInterface instead of ResourceInterface. [BREAKING]

    Removed

    • Method getNodeClass was removed from NodeInterface. [BREAKING]
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0-beta4(Oct 11, 2018)

  • 1.0.0-beta3(Oct 11, 2018)

  • 1.0.0-beta2(Sep 26, 2018)

    Added

    • Node renderer Contentful\StructuredText\NodeRenderer\CatchAll can be used to avoid having the main renderer throw an exception in the event of an unsupported node. Use it like this:
      $renderer = new Contentful\StructuredText\Renderer();
      $renderer->appendNodeRenderer(new Contentful\StructuredText\NodeRenderer\CatchAll());
      

      It's important to use the appendNodeRenderer method to make the main renderer use it as last resort, otherwise, it will intercept all calls to other nodes.

    • NodeInterface now includes method getNodeClass, for exposing whether a node is of type block or inline.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0-beta1(Sep 13, 2018)

Laminas\Text is a component to work on text strings

laminas-text This package is considered feature-complete, and is now in security-only maintenance mode, following a decision by the Technical Steering

Laminas Project 38 Dec 31, 2022
Zend\Text is a component to work on text strings from Zend Framework

zend-text Repository abandoned 2019-12-31 This repository has moved to laminas/laminas-text. Zend\Text is a component to work on text strings. It cont

Zend Framework 31 Jan 24, 2021
RRR makes structured data for WordPress really rich, and really easy.

Really Rich Results - JSON-LD Structured Data (Google Rich Results) for WordPress Search engines are putting more weight on structured data than ever

Pagely 22 Dec 1, 2022
Build lightning-fast and feature-rich websites with ProcessWire.

WIREKIT Core Build lightning-fast and feature-rich websites with ProcessWire. Website: wirekit.dev (in plans) Demo: start.wirekit.dev/core/ Updates: W

Ivan Milincic 10 Nov 3, 2022
A set of utilities for working with vk api!

vk-utils Документация на русском языке Installation composer require labile/vk-utils How to use it? Simple example use Astaroth\VkUtils\Client; $api

null 1 Jan 3, 2022
Open-source library used in Gigadrive projects with common PHP utilities

PHP Commons This library provides PHP utilities used in Gigadrive projects, provided for the open-source community. Functions are registered globally

Gigadrive UG 3 Nov 10, 2021
This is php utilities

PHP-UTILITY This is php utilities. Requirements PHP >= 7.4 Curl extension for PHP7 must be enabled. Download Using Composer From your project director

null 2 Aug 28, 2022
Magento-bulk - Bulk Import/Export helper scripts and CLI utilities for Magento Commerce

Magento Bulk Bulk operations for Magento. Configuration Copy config.php.sample to config.php and edit it. Product Attribute Management List All Attrib

Bippo Indonesia 23 Dec 20, 2022
This library provides a collection of native enum utilities (traits) which you almost always need in every PHP project.

This library provides a collection of native enum utilities (traits) which you almost always need in every PHP project.

DIVE 20 Nov 11, 2022
Utilities to scan PHP code and generate class maps.

composer/class-map-generator Utilities to generate class maps and scan PHP code. Installation Install the latest version with: $ composer require comp

Composer 55 Dec 26, 2022
Utilities for concurrent programming of PocketMine-MP plugins.

Utilities for concurrent programming of PocketMine-MP plugins Overview Plugin that implements the pthreads channels and in the future, promises (which

Dmitry Uzyanov 0 Aug 15, 2022
Testing utilities for the psr/log package that backs the PSR-3 specification.

FIG - Log Test Testing utilities for the psr/log package that backs the PSR-3 specification. Psr\Log\Test\LoggerInterfaceTest provides a base test cla

PHP-FIG 3 Nov 19, 2022
TEC UTilities (or tut) are a collection of tools for managing plugins.

TEC Utilities TEC UTilities (or tut) are a collection of tools for managing plugins. /^\ L L /

The Events Calendar 5 Dec 2, 2022
A collection of useful codes and utilities for WordPress plugin development..

WordPress Utils A collection of useful codes and utilities for WordPress plugin development. These simplifies common tasks and promote code reusabilit

weDevs 5 Jun 9, 2023
A collection of command-line utilities to aid in debugging browser engines.

Browser debug utilities This project contains several scripts that make the process of debugging browser engines much easier (some special cases excep

Clay Freeman 5 May 29, 2023
A PHP component to convert HTML into a plain text format

html2text html2text is a very simple script that uses DOM methods to convert HTML into a format similar to what would be rendered by a browser - perfe

Jevon Wright 423 Dec 29, 2022
[READ-ONLY] CakePHP Utility classes such as Inflector, Text, Hash, Security and Xml. This repo is a split of the main code that can be found in https://github.com/cakephp/cakephp

CakePHP Utility Classes This library provides a range of utility classes that are used throughout the CakePHP framework What's in the toolbox? Hash A

CakePHP 112 Feb 15, 2022
A PHP library to convert text to speech using various services

speaker A PHP library to convert text to speech using various services

Craig Duncan 98 Nov 27, 2022
Xenon\LaravelBDSms is a sms gateway package for sending text message to Bangladeshi mobile numbers using several gateways like sslcommerz, greenweb, dianahost,metronet in Laravel framework

Xenon\LaravelBDSms is a sms gateway package for sending text message to Bangladeshi mobile numbers using several gateways for Laravel. You should use

Ariful Islam 95 Jan 3, 2023