contentful / rich-text.php

Utilities for the Contentful Rich Text
https://www.contentful.com
MIT License
12 stars 9 forks source link

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

Closed e1himself closed 4 years ago

e1himself commented 4 years ago

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.

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} ```
e1himself commented 4 years ago

The only way I see to fix it is to lazy-resolve links inside EntryHyperlink nodes.

Something like this.

EntryHyperlink mapper:

class EntryHyperlink implements NodeMapperInterface
{
    /**
     * {@inheritdoc}
     */
    public function map(ParserInterface $parser, LinkResolverInterface $linkResolver, array $data): NodeInterface
    {
        $linkData = $data['data']['target']['sys'];
        $link = new Link($linkData['id'], $linkData['linkType']);

        return new NodeClass(
            $parser->parseCollection($data['content']),
            $data['data']['title'] ?? '',
            $link,
            $linkResolver
        );
    }
}

EntryHyperlink Node:

class EntryHyperlink extends InlineNode
{
    /**
     * @var string
     */
    protected $title;

    /**
     * @var \Contentful\Core\Api\Link
     */
    protected $link;

    /**
     * @var \Contentful\Core\Api\LinkResolverInterface
     */
    protected $linkResolver;

    public function __construct(array $content, string $title, Link $link, LinkResolverInterface $linkResolver)
    {
        parent::__construct($content);
        $this->title = $title;
        $this->link = $link;
        $this->linkResolver = $linkResolver;
    }

    public function getEntry(): EntryInterface
    {
        return $this->linkResolver->resolveLink($this->link);
    }

    // ...
}
e1himself commented 4 years ago

I've prepared a PR to fix it. Here: #45

pgrigoruta commented 4 years ago

Thanks for the fix @e1himself , however it looks like for now at least some test cases are failing:

`There was 1 error:

1) Contentful\Tests\RichText\Unit\NodeRenderer\EmbeddedEntryBlockTest::testRendering TypeError: Argument 2 passed to Contentful\RichText\Node\EmbeddedEntryBlock::__construct() must implement interface Contentful\RichText\NodeMapper\Reference\EntryReferenceInterface, instance of Contentful\Core\Api\Link given, called in /Users/paul/www/contentful/rich-text.php/tests/Unit/NodeRenderer/EmbeddedEntryBlockTest.php on line 29

/Users/paul/www/contentful/rich-text.php/src/Node/EmbeddedEntryBlock.php:30 /Users/paul/www/contentful/rich-text.php/tests/Unit/NodeRenderer/EmbeddedEntryBlockTest.php:29

--

There were 3 failures:

1) Contentful\Tests\RichText\Unit\ParserTest::testMapperException with data set #3 ('embedded-entry-block') Failed asserting that Contentful\RichText\Node\EmbeddedEntryBlock Object (...) is an instance of class "Contentful\RichText\Node\Nothing".

/Users/paul/www/contentful/rich-text.php/tests/Unit/ParserTest.php:109

2) Contentful\Tests\RichText\Unit\ParserTest::testMapperException with data set #4 ('embedded-entry-inline') Failed asserting that Contentful\RichText\Node\EmbeddedEntryInline Object (...) is an instance of class "Contentful\RichText\Node\Nothing".

/Users/paul/www/contentful/rich-text.php/tests/Unit/ParserTest.php:109

3) Contentful\Tests\RichText\Unit\ParserTest::testMapperException with data set #5 ('entry-hyperlink') Failed asserting that Contentful\RichText\Node\EntryHyperlink Object (...) is an instance of class "Contentful\RichText\Node\Nothing".

/Users/paul/www/contentful/rich-text.php/tests/Unit/ParserTest.php:109

ERRORS! Tests: 190, Assertions: 536, Errors: 1, Failures: 3.`

Alternatively, I think we have took a different approach here. Did you check the latest version (4.1.4) of the SDK? I am specifically referring to https://github.com/contentful/contentful.php/commit/e29d218f8eb5bee69168d3cefc3e72d7a38dacd4 , which should fix the infinite recursion caused by endlessly trying to resolve links. If I am understanding your issue correctly, this should fix it, although in a very different way.

If you already upgraded to 4.1.4 and still have the issue, please paste the exact code that reproduces it as I'd like to see if we can come up with a lower impact solution.

e1himself commented 4 years ago

Did you check the latest version (4.1.4) of the SDK.

Yes, I did. I even reported another problem with it here: https://github.com/contentful/contentful.php/issues/280

The 4.1.2 / 4.1.3 / 4.1.4 release is targeting a problem with node that references itself. But this problem here is different.

pgrigoruta commented 4 years ago

Thanks, let me have a better look.

e1himself commented 4 years ago

please paste the exact code that reproduces it

@pgrigoruta

Please do this:

  1. Set up a demo space in Contentful

    • Create one content type (page) with one Rich Text field: body.
    • Create two entries. Every entry should reference the other one with a hyperlink in its rich text body.
  2. Fetch one of the entities over API with XDebug disabled.

e1himself commented 4 years ago

@pgrigoruta

however it looks like for now at least some test cases are failing

Thanks for pointing out! :+1: Fixed with bd271ecb29407166174866c3e84c04d8867eb354

And also I've added a new test specifically for the deferred dereferencing: a2c1a4997a11305a6417f7c7dbd957a6161e818d


I'd like to see if we can come up with a lower impact solution.

I'm all for it! :)

I just see no other choice.

Here's the problem: the Delivery Client fetches an entry, builds it and then saves it into resource pool and into cache backend at the same time. So we want the entry to be complete at this stage -- everything that should be fetched has to be fetched before storing into pool/cache.

This means that we cannot fetch all entry nested references recursively before storing it, as long as Contentful allows us to have reference loops.

So the only way to store entry is to not fetch all references upfront. But postpone that after an entry is pooled, cached and then being used. Thus the solution.

I also do understand that this is a BC break. Should we consider bumping the library version to 2.0 to properly follow semver?

pgrigoruta commented 4 years ago

Thanks @e1himself , this makes sense.

Besides a few coding standards changes, see https://github.com/contentful/rich-text.php/commit/6933ae3a81b5464279a93bbdbc9fd4b8f6d68831

The defined methods for getEntry() look like they need to return a ResourceInterface , not a EntryInterface. That is dictated by https://github.com/contentful/rich-text.php/pull/45/files#diff-1098ff1ee0b804b58878d22cf97a9888R51 . Let me know if you see another solution. By the way, we use phpstan to catch this kind of type errors:

$([ -f phpstan.phar ] && echo "php phpstan.phar" || echo "phpstan") analyse --level=max src/

e1himself commented 4 years ago

@pgrigoruta

getEntry() looks like they need to return a ResourceInterface

Thanks for fixing it Paul! :+1:

However, I'm not sure about this change.

Firstly, there's a check inside EntryReference disallowing links to anything else except Entry. Thus it's guaranteed that LinkResolver will return an instance of Entry.

Secondly, the interface and class names and even getEntry() method are mentioning Entry, thus it should return an instance implementing EntryInterface.


Would it maybe be better if we make phpstan happy by fixing this code here: https://github.com/contentful/rich-text.php/blob/a2c1a4997a11305a6417f7c7dbd957a6161e818d/src/NodeMapper/Reference/EntryReference.php#L50-L52

into something like this:

if (is_null($this->entry)) {
    $resource = $this->linkResolver->resolveLink($this->link);

    if ($resource instanceof EntryInterface) {
        return $this->entry = $resource;
    }

    throw new RuntimeException(sprintf(
        'A link has been resolved to an instance of %s, but %s is expected. This should never happen.',
        get_class($resource),
        EntryInterface::class
    ));
}

return $this->entry;

What do you think about this?

Thanks!

pgrigoruta commented 4 years ago

Yes, this looks like a better idea, thanks! Please see https://github.com/contentful/rich-text.php/commit/36449f140847c9eb2b28b34d09c82877c461244c , I have also added a few test cases to cover for the new branches introduced. Let me know if you have anymore feedback, otherwise I will pass this through our internal QA.

e1himself commented 4 years ago

@pgrigoruta I've gone over the changeset and everything looks great! Many thanks! :+1:

pgrigoruta commented 4 years ago

@e1himself many thanks to you for providing most of the solution! This has been merged and released as a new major version.