diff --git a/packages/guides-restructured-text/src/RestructuredText/Directives/ImageDirective.php b/packages/guides-restructured-text/src/RestructuredText/Directives/ImageDirective.php index 855b5ec1b..29730bad2 100644 --- a/packages/guides-restructured-text/src/RestructuredText/Directives/ImageDirective.php +++ b/packages/guides-restructured-text/src/RestructuredText/Directives/ImageDirective.php @@ -14,12 +14,21 @@ namespace phpDocumentor\Guides\RestructuredText\Directives; use phpDocumentor\Guides\Nodes\ImageNode; +use phpDocumentor\Guides\Nodes\Inline\DocReferenceNode; +use phpDocumentor\Guides\Nodes\Inline\HyperLinkNode; +use phpDocumentor\Guides\Nodes\Inline\LinkInlineNode; +use phpDocumentor\Guides\Nodes\Inline\ReferenceNode; use phpDocumentor\Guides\Nodes\Node; use phpDocumentor\Guides\ReferenceResolvers\DocumentNameResolverInterface; use phpDocumentor\Guides\RestructuredText\Parser\BlockContext; use phpDocumentor\Guides\RestructuredText\Parser\Directive; use function dirname; +use function filter_var; +use function preg_match; + +use const FILTER_VALIDATE_EMAIL; +use const FILTER_VALIDATE_URL; /** * Renders an image, example : @@ -30,6 +39,12 @@ */ final class ImageDirective extends BaseDirective { + /** @see https://regex101.com/r/9dUrzu/3 */ + public const REFERENCE_REGEX = '/^([a-zA-Z0-9-_]+)_$/'; + + /** @see https://regex101.com/r/6vPoiA/2 */ + public const REFERENCE_ESCAPED_REGEX = '/^`([^`]+)`_$/'; + public function __construct( private readonly DocumentNameResolverInterface $documentNameResolver, ) { @@ -45,11 +60,38 @@ public function processNode( BlockContext $blockContext, Directive $directive, ): Node { - return new ImageNode( + $node = new ImageNode( $this->documentNameResolver->absoluteUrl( dirname($blockContext->getDocumentParserContext()->getContext()->getCurrentAbsolutePath()), $directive->getData(), ), ); + if ($directive->hasOption('target')) { + $targetReference = (string) $directive->getOption('target')->getValue(); + $node->setTarget($this->resolveLinkTarget($targetReference)); + } + + return $node; + } + + private function resolveLinkTarget(string $targetReference): LinkInlineNode + { + if (filter_var($targetReference, FILTER_VALIDATE_EMAIL)) { + return new HyperLinkNode('', $targetReference); + } + + if (filter_var($targetReference, FILTER_VALIDATE_URL)) { + return new HyperLinkNode('', $targetReference); + } + + if (preg_match(self::REFERENCE_REGEX, $targetReference, $matches)) { + return new ReferenceNode($matches[1], ''); + } + + if (preg_match(self::REFERENCE_ESCAPED_REGEX, $targetReference, $matches)) { + return new ReferenceNode($matches[1], ''); + } + + return new DocReferenceNode($targetReference, ''); } } diff --git a/packages/guides/resources/config/guides.php b/packages/guides/resources/config/guides.php index 94e69a63e..a69251838 100644 --- a/packages/guides/resources/config/guides.php +++ b/packages/guides/resources/config/guides.php @@ -28,6 +28,7 @@ use phpDocumentor\Guides\ReferenceResolvers\DocumentNameResolverInterface; use phpDocumentor\Guides\ReferenceResolvers\EmailReferenceResolver; use phpDocumentor\Guides\ReferenceResolvers\ExternalReferenceResolver; +use phpDocumentor\Guides\ReferenceResolvers\ImageReferenceResolverPreRender; use phpDocumentor\Guides\ReferenceResolvers\Interlink\DefaultInventoryLoader; use phpDocumentor\Guides\ReferenceResolvers\Interlink\DefaultInventoryRepository; use phpDocumentor\Guides\ReferenceResolvers\Interlink\InventoryLoader; @@ -192,6 +193,8 @@ ->set(ReferenceResolverPreRender::class) ->tag('phpdoc.guides.prerenderer') + ->set(ImageReferenceResolverPreRender::class) + ->tag('phpdoc.guides.prerenderer') ->set(InMemoryRendererFactory::class) ->arg('$renderSets', tagged_iterator('phpdoc.renderer.typerenderer', 'format')) diff --git a/packages/guides/resources/template/html/body/image.html.twig b/packages/guides/resources/template/html/body/image.html.twig index 9bc9eeb05..9564e81cf 100644 --- a/packages/guides/resources/template/html/body/image.html.twig +++ b/packages/guides/resources/template/html/body/image.html.twig @@ -1,3 +1,4 @@ +{% if node.target %}{% endif %} +{% if node.target %}{% endif %} diff --git a/packages/guides/src/Nodes/ImageNode.php b/packages/guides/src/Nodes/ImageNode.php index cb4f15256..14cbd9a57 100644 --- a/packages/guides/src/Nodes/ImageNode.php +++ b/packages/guides/src/Nodes/ImageNode.php @@ -13,6 +13,19 @@ namespace phpDocumentor\Guides\Nodes; +use phpDocumentor\Guides\Nodes\Inline\LinkInlineNode; + final class ImageNode extends TextNode { + public LinkInlineNode|null $target = null; + + public function getTarget(): LinkInlineNode|null + { + return $this->target; + } + + public function setTarget(LinkInlineNode|null $target): void + { + $this->target = $target; + } } diff --git a/packages/guides/src/ReferenceResolvers/ImageReferenceResolverPreRender.php b/packages/guides/src/ReferenceResolvers/ImageReferenceResolverPreRender.php new file mode 100644 index 000000000..bb211a428 --- /dev/null +++ b/packages/guides/src/ReferenceResolvers/ImageReferenceResolverPreRender.php @@ -0,0 +1,62 @@ +getTarget() === null) { + return $node; + } + + $referenceLinkNode = $node->getTarget(); + $messages = new Messages(); + $resolved = $this->referenceResolver->resolve($referenceLinkNode, $renderContext, $messages); + if (!$resolved) { + $this->logger->warning( + $messages->getLastWarning()?->getMessage() ?? sprintf( + 'Target %s of image could not be resolved in %s', + $referenceLinkNode->getTargetReference(), + $renderContext->getCurrentFileName(), + ), + array_merge($renderContext->getLoggerInformation(), $messages->getLastWarning()?->getDebugInfo() ?? []), + ); + } + + return $node; + } +} diff --git a/tests/Integration/tests/images/image-target/expected/images/hero2-illustration.svg b/tests/Integration/tests/images/image-target/expected/images/hero2-illustration.svg new file mode 100644 index 000000000..002f8feff --- /dev/null +++ b/tests/Integration/tests/images/image-target/expected/images/hero2-illustration.svg @@ -0,0 +1,180 @@ + diff --git a/tests/Integration/tests/images/image-target/expected/index.html b/tests/Integration/tests/images/image-target/expected/index.html new file mode 100644 index 000000000..8834b0852 --- /dev/null +++ b/tests/Integration/tests/images/image-target/expected/index.html @@ -0,0 +1,61 @@ + +
Lorem Ipsum Dolor.
+