Skip to content

Commit adde014

Browse files
authored
Merge pull request #797 from phpDocumentor/task/improve-link-reporting
!!![TASK] Warn only once when a reference cannot be resolved
2 parents 9fc8238 + d977694 commit adde014

14 files changed

+118
-55
lines changed

packages/guides/src/ReferenceResolvers/AnchorHyperlinkResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function __construct(
2424
) {
2525
}
2626

27-
public function resolve(LinkInlineNode $node, RenderContext $renderContext): bool
27+
public function resolve(LinkInlineNode $node, RenderContext $renderContext, Messages $messages): bool
2828
{
2929
if (!$node instanceof HyperLinkNode) {
3030
return false;

packages/guides/src/ReferenceResolvers/AnchorReferenceResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function __construct(
2424
) {
2525
}
2626

27-
public function resolve(LinkInlineNode $node, RenderContext $renderContext): bool
27+
public function resolve(LinkInlineNode $node, RenderContext $renderContext, Messages $messages): bool
2828
{
2929
if (!$node instanceof ReferenceNode) {
3030
return false;

packages/guides/src/ReferenceResolvers/DelegatingReferenceResolver.php

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,25 @@
66

77
use phpDocumentor\Guides\Nodes\Inline\LinkInlineNode;
88
use phpDocumentor\Guides\RenderContext;
9-
use Psr\Log\LoggerInterface;
10-
11-
use function sprintf;
129

1310
/**
1411
* Resolves the URL for all inline link nodes using reference resolvers.
1512
*/
1613
final class DelegatingReferenceResolver
1714
{
1815
/** @param iterable<ReferenceResolver> $resolvers */
19-
public function __construct(private readonly iterable $resolvers, private readonly LoggerInterface $logger)
16+
public function __construct(private readonly iterable $resolvers)
2017
{
2118
}
2219

23-
public function resolve(LinkInlineNode $node, RenderContext $renderContext): void
20+
public function resolve(LinkInlineNode $node, RenderContext $renderContext, Messages $messages): bool
2421
{
2522
foreach ($this->resolvers as $resolver) {
26-
if ($resolver->resolve($node, $renderContext)) {
27-
return;
23+
if ($resolver->resolve($node, $renderContext, $messages)) {
24+
return true;
2825
}
2926
}
3027

31-
$this->logger->warning(
32-
sprintf(
33-
'Reference %s could not be resolved in %s',
34-
$node->getTargetReference(),
35-
$renderContext->getCurrentFileName(),
36-
),
37-
$renderContext->getLoggerInformation(),
38-
);
28+
return false;
3929
}
4030
}

packages/guides/src/ReferenceResolvers/DocReferenceResolver.php

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
use phpDocumentor\Guides\Nodes\Inline\LinkInlineNode;
99
use phpDocumentor\Guides\RenderContext;
1010
use phpDocumentor\Guides\Renderer\UrlGenerator\UrlGeneratorInterface;
11-
use Psr\Log\LoggerInterface;
1211

13-
use function array_merge;
1412
use function sprintf;
1513

1614
class DocReferenceResolver implements ReferenceResolver
@@ -20,11 +18,10 @@ class DocReferenceResolver implements ReferenceResolver
2018
public function __construct(
2119
private readonly UrlGeneratorInterface $urlGenerator,
2220
private readonly DocumentNameResolverInterface $documentNameResolver,
23-
private readonly LoggerInterface $logger,
2421
) {
2522
}
2623

27-
public function resolve(LinkInlineNode $node, RenderContext $renderContext): bool
24+
public function resolve(LinkInlineNode $node, RenderContext $renderContext, Messages $messages): bool
2825
{
2926
if (!$node instanceof DocReferenceNode) {
3027
return false;
@@ -38,14 +35,11 @@ public function resolve(LinkInlineNode $node, RenderContext $renderContext): boo
3835

3936
$document = $renderContext->getProjectNode()->findDocumentEntry($canonicalDocumentName);
4037
if ($document === null) {
41-
$this->logger->warning(
42-
sprintf(
43-
'Document with name "%s" not found, required in file "%s".',
44-
$canonicalDocumentName,
45-
$renderContext->getCurrentFileName(),
46-
),
47-
array_merge($renderContext->getLoggerInformation(), $node->getDebugInformation()),
48-
);
38+
$messages->addWarning(new Message(sprintf(
39+
'Document with name "%s" not found, required in file "%s".',
40+
$canonicalDocumentName,
41+
$renderContext->getCurrentFileName(),
42+
)));
4943

5044
return false;
5145
}

packages/guides/src/ReferenceResolvers/EmailReferenceResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class EmailReferenceResolver implements ReferenceResolver
1818
{
1919
public final const PRIORITY = -100;
2020

21-
public function resolve(LinkInlineNode $node, RenderContext $renderContext): bool
21+
public function resolve(LinkInlineNode $node, RenderContext $renderContext, Messages $messages): bool
2222
{
2323
if (filter_var($node->getTargetReference(), FILTER_VALIDATE_EMAIL)) {
2424
$node->setUrl('mailto:' . $node->getTargetReference());

packages/guides/src/ReferenceResolvers/ExternalReferenceResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class ExternalReferenceResolver implements ReferenceResolver
2828
public final const PRIORITY = -100;
2929
final public const SUPPORTED_SCHEMAS = '(?:aaa|aaas|about|acap|acct|acd|acr|adiumxtra|adt|afp|afs|aim|amss|android|appdata|apt|ar|ark|at|attachment|aw|barion|bb|beshare|bitcoin|bitcoincash|blob|bolo|browserext|cabal|calculator|callto|cap|cast|casts|chrome|chrome-extension|cid|coap|coap+tcp|coap+ws|coaps|coaps+tcp|coaps+ws|com-eventbrite-attendee|content|content-type|crid|cstr|cvs|dab|dat|data|dav|dhttp|diaspora|dict|did|dis|dlna-playcontainer|dlna-playsingle|dns|dntp|doi|dpp|drm|drop|dtmi|dtn|dvb|dvx|dweb|ed2k|eid|elsi|embedded|ens|ethereum|example|facetime|fax|feed|feedready|fido|file|filesystem|finger|first-run-pen-experience|fish|fm|ftp|fuchsia-pkg|geo|gg|git|gitoid|gizmoproject|go|gopher|graph|grd|gtalk|h323|ham|hcap|hcp|http|https|hxxp|hxxps|hydrazone|hyper|iax|icap|icon|im|imap|info|iotdisco|ipfs|ipn|ipns|ipp|ipps|irc|irc6|ircs|iris|iris\.beep|iris\.lwz|iris\.xpc|iris\.xpcs|isostore|itms|jabber|jar|jms|keyparc|lastfm|lbry|ldap|ldaps|leaptofrogans|lorawan|lpa|lvlt|magnet|mailserver|mailto|maps|market|matrix|message|microsoft\.windows\.camera|microsoft\.windows\.camera\.multipicker|microsoft\.windows\.camera\.picker|mid|mms|modem|mongodb|moz|ms-access|ms-appinstaller|ms-browser-extension|ms-calculator|ms-drive-to|ms-enrollment|ms-excel|ms-eyecontrolspeech|ms-gamebarservices|ms-gamingoverlay|ms-getoffice|ms-help|ms-infopath|ms-inputapp|ms-launchremotedesktop|ms-lockscreencomponent-config|ms-media-stream-id|ms-meetnow|ms-mixedrealitycapture|ms-mobileplans|ms-newsandinterests|ms-officeapp|ms-people|ms-project|ms-powerpoint|ms-publisher|ms-remotedesktop|ms-remotedesktop-launch|ms-restoretabcompanion|ms-screenclip|ms-screensketch|ms-search|ms-search-repair|ms-secondary-screen-controller|ms-secondary-screen-setup|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-connectabledevices|ms-settings-displays-topology|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|ms-spd|ms-stickers|ms-sttoverlay|ms-transit-to|ms-useractivityset|ms-virtualtouchpad|ms-visio|ms-walk-to|ms-whiteboard|ms-whiteboard-cmd|ms-word|msnim|msrp|msrps|mss|mt|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|num|ocf|oid|onenote|onenote-cmd|opaquelocktoken|openpgp4fpr|otpauth|p1|pack|palm|paparazzi|payment|payto|pkcs11|platform|pop|pres|prospero|proxy|pwid|psyc|pttp|qb|query|quic-transport|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|sarif|secondlife|secret-token|service|session|sftp|sgn|shc|shttp (OBSOLETE)|sieve|simpleledger|simplex|sip|sips|skype|smb|smp|sms|smtp|snews|snmp|soap\.beep|soap\.beeps|soldat|spiffe|spotify|ssb|ssh|starknet|steam|stun|stuns|submit|svn|swh|swid|swidpath|tag|taler|teamspeak|tel|teliaeid|telnet|tftp|things|thismessage|tip|tn3270|tool|turn|turns|tv|udp|unreal|upt|urn|ut2004|uuid-in-package|v-event|vemmi|ventrilo|ves|videotex|vnc|view-source|vscode|vscode-insiders|vsls|w3|wais|web3|wcr|webcal|web+ap|wifi|wpid|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc\.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s)';
3030

31-
public function resolve(LinkInlineNode $node, RenderContext $renderContext): bool
31+
public function resolve(LinkInlineNode $node, RenderContext $renderContext, Messages $messages): bool
3232
{
3333
if (str_starts_with($node->getTargetReference(), '#')) {
3434
$node->setUrl($node->getTargetReference());

packages/guides/src/ReferenceResolvers/InterlinkReferenceResolver.php

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@
99
use phpDocumentor\Guides\Nodes\Inline\DocReferenceNode;
1010
use phpDocumentor\Guides\Nodes\Inline\LinkInlineNode;
1111
use phpDocumentor\Guides\RenderContext;
12-
use Psr\Log\LoggerInterface;
1312

14-
use function array_merge;
1513
use function sprintf;
1614

1715
class InterlinkReferenceResolver implements ReferenceResolver
@@ -20,11 +18,10 @@ class InterlinkReferenceResolver implements ReferenceResolver
2018

2119
public function __construct(
2220
private readonly InventoryRepository $inventoryRepository,
23-
private readonly LoggerInterface $logger,
2421
) {
2522
}
2623

27-
public function resolve(LinkInlineNode $node, RenderContext $renderContext): bool
24+
public function resolve(LinkInlineNode $node, RenderContext $renderContext, Messages $messages): bool
2825
{
2926
if (!$node instanceof CrossReferenceNode || $node->getInterlinkDomain() === '') {
3027
return false;
@@ -33,13 +30,15 @@ public function resolve(LinkInlineNode $node, RenderContext $renderContext): boo
3330
$domain = $node->getInterlinkDomain();
3431
$target = $node->getTargetReference();
3532
if (!$this->inventoryRepository->hasInventory($domain)) {
36-
$this->logger->warning(
37-
sprintf(
38-
'Inventory with name "%s" could not be resolved in file "%s". ',
39-
$domain,
40-
$renderContext->getCurrentFileName(),
33+
$messages->addWarning(
34+
new Message(
35+
sprintf(
36+
'Inventory with name "%s" could not be resolved in file "%s". ',
37+
$domain,
38+
$renderContext->getCurrentFileName(),
39+
),
40+
$node->getDebugInformation(),
4141
),
42-
array_merge($renderContext->getLoggerInformation(), $node->getDebugInformation()),
4342
);
4443

4544
return false;
@@ -48,31 +47,31 @@ public function resolve(LinkInlineNode $node, RenderContext $renderContext): boo
4847
$inventory = $this->inventoryRepository->getInventory($domain);
4948
$group = $node instanceof DocReferenceNode ? 'std:doc' : 'std:label';
5049
if (!$inventory->hasInventoryGroup($group)) {
51-
$this->logger->warning(
50+
$messages->addWarning(new Message(
5251
sprintf(
5352
'Inventory with name "%s" does not contain group %s, required in file "%s". ',
5453
$domain,
5554
$group,
5655
$renderContext->getCurrentFileName(),
5756
),
58-
array_merge($renderContext->getLoggerInformation(), $node->getDebugInformation()),
59-
);
57+
$node->getDebugInformation(),
58+
));
6059

6160
return false;
6261
}
6362

6463
$inventoryGroup = $inventory->getInventory($group);
6564
if (!$inventoryGroup->hasLink($target)) {
66-
$this->logger->warning(
65+
$messages->addWarning(new Message(
6766
sprintf(
6867
'Link with name "%s:%s" not found in group "%s", required in file "%s".',
6968
$domain,
7069
$target,
7170
$group,
7271
$renderContext->getCurrentFileName(),
7372
),
74-
array_merge($renderContext->getLoggerInformation(), $node->getDebugInformation()),
75-
);
73+
$node->getDebugInformation(),
74+
));
7675

7776
return false;
7877
}

packages/guides/src/ReferenceResolvers/InternalReferenceResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class InternalReferenceResolver implements ReferenceResolver
1111
{
1212
public final const PRIORITY = 100;
1313

14-
public function resolve(LinkInlineNode $node, RenderContext $renderContext): bool
14+
public function resolve(LinkInlineNode $node, RenderContext $renderContext, Messages $messages): bool
1515
{
1616
$link = $renderContext->getLink($node->getTargetReference());
1717
if ($link) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Guides\ReferenceResolvers;
6+
7+
class Message
8+
{
9+
/** @param array<string, mixed> $debugInfo */
10+
public function __construct(
11+
private readonly string $message,
12+
private readonly array $debugInfo = [],
13+
) {
14+
}
15+
16+
public function getMessage(): string
17+
{
18+
return $this->message;
19+
}
20+
21+
/** @return mixed[] */
22+
public function getDebugInfo(): array
23+
{
24+
return $this->debugInfo;
25+
}
26+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Guides\ReferenceResolvers;
6+
7+
use function end;
8+
9+
final class Messages
10+
{
11+
/** @var list<Message> */
12+
private array $warnings = [];
13+
14+
public function addWarning(Message $warning): void
15+
{
16+
$this->warnings[] = $warning;
17+
}
18+
19+
/** @return Message[] */
20+
public function getWarnings(): array
21+
{
22+
return $this->warnings;
23+
}
24+
25+
public function getLastWarning(): Message|null
26+
{
27+
if (!empty($this->warnings)) {
28+
return end($this->warnings);
29+
}
30+
31+
return null;
32+
}
33+
}

0 commit comments

Comments
 (0)