99use Aws \Api \Service as Api ;
1010use Aws \Api \StructureShape ;
1111use Aws \Api \DocModel ;
12+ use GuzzleHttp \Client ;
1213use TokenReflection \Broker ;
1314use TokenReflection \ReflectionBase ;
1415use TokenReflection \ReflectionFunction ;
2122 */
2223class DocsBuilder
2324{
25+ private const EXAMPLES_URL = 'https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/php_code_examples.html ' ;
26+
2427 /** @var string HTML template to replace {{ contents }} */
2528 private $ template ;
2629
@@ -48,6 +51,9 @@ class DocsBuilder
4851 /** @var bool Enables writing of build-issues.log file when set. */
4952 private $ issueLoggingEnabled ;
5053
54+ /** @var Client */
55+ private $ guzzleClient ;
56+
5157 /** @var array Printable error names for build-issues.log file */
5258 private static $ ERROR_PRINT_NAMES =[
5359 E_ERROR => 'Error ' ,
@@ -72,7 +78,8 @@ public function __construct(
7278 $ baseUrl ,
7379 array $ quickLinks ,
7480 array $ sources ,
75- $ issueLoggingEnabled = false
81+ $ issueLoggingEnabled = false ,
82+ ?Client $ guzzleClient = null
7683 ) {
7784 $ this ->apiProvider = $ provider ;
7885 $ this ->outputDir = $ outputDir ;
@@ -81,6 +88,7 @@ public function __construct(
8188 $ this ->quickLinks = $ quickLinks ;
8289 $ this ->sources = $ sources ;
8390 $ this ->issueLoggingEnabled = $ issueLoggingEnabled ;
91+ $ this ->guzzleClient = $ guzzleClient ?? new Client ();
8492 }
8593
8694 public function build ()
@@ -178,8 +186,8 @@ private function updateQuickLinks(array $services)
178186 // Determine which services in the provided array should have a quick link
179187 $ services = array_filter ($ services , function (array $ versions ) {
180188 return 0 < count (array_filter ($ versions , function (Service $ service ) {
181- return in_array ($ service ->name , $ this ->quickLinks );
182- }));
189+ return in_array ($ service ->name , $ this ->quickLinks );
190+ }));
183191 });
184192
185193 // Drop all but the latest version of each service from the array
@@ -448,10 +456,62 @@ private function loadExamples($name, $version)
448456 }
449457 }
450458
459+ /**
460+ * Fetches service examples from the AWS SDK for PHP Developer Guide.
461+ *
462+ * @return array Associative array of service ID => documentation URL
463+ */
464+ private function fetchServiceExamplesFromDocs (): array
465+ {
466+ try {
467+ $ response = $ this ->guzzleClient ->get (self ::EXAMPLES_URL );
468+ $ html = (string ) $ response ->getBody ();
469+ } catch (\Exception $ e ) {
470+ fwrite (STDERR , "Failed to fetch examples from docs: " . $ e ->getMessage () . "\n" );
471+ return [];
472+ }
473+
474+ $ doc = new \DOMDocument ();
475+ @$ doc ->loadHTML ($ html );
476+ $ xpath = new \DOMXPath ($ doc );
477+
478+ $ canonicalNode = $ xpath ->query ('//link[@rel="canonical"]/@href ' )->item (0 );
479+ if (!$ canonicalNode ) {
480+ fwrite (STDERR , "Could not find canonical URL in examples page \n" );
481+ return [];
482+ }
483+ $ baseUrl = dirname ($ canonicalNode ->nodeValue );
484+
485+ $ links = $ xpath ->query ('//div[@class="highlights"]//ul//a ' );
486+
487+ $ services = [];
488+ foreach ($ links as $ link ) {
489+ $ href = $ link ->getAttribute ('href ' );
490+
491+ // Extract service ID: remove "php_", "_code_examples.html", and leading "./"
492+ $ serviceId = preg_replace ('/^\.\// ' , '' , $ href );
493+ $ serviceId = preg_replace ('/^php_/ ' , '' , $ serviceId );
494+ $ serviceId = preg_replace ('/_code_examples\.html$/ ' , '' , $ serviceId );
495+
496+ $ fullUrl = $ baseUrl . '/ ' . ltrim ($ href , './ ' );
497+
498+ $ services [$ serviceId ] = $ fullUrl ;
499+ }
500+
501+ fwrite (STDOUT , "Fetched " . count ($ services ) . " service examples from AWS docs \n" );
502+
503+ return $ services ;
504+ }
505+
451506 private function updateClients (array $ services )
452507 {
453508 fwrite (STDOUT , "Updating client pages with service links \n" );
454509
510+ // Fetch new examples once for all services
511+ $ newExamples = $ this ->fetchServiceExamplesFromDocs ();
512+ $ legacyExamples = require __DIR__ . '/../config/dev-guide-service-examples.php ' ;
513+ $ serviceIdMap = $ legacyExamples ['_service_id_map ' ] ?? [];
514+
455515 foreach ($ services as $ versions ) {
456516 krsort ($ versions );
457517 $ service = reset ($ versions );
@@ -483,16 +543,31 @@ private function updateClients(array $services)
483543 }
484544 $ html .= '</ul></article> ' ;
485545
486- // Add Examples (from the developer guide) section, where applicable
487- $ serviceExamples = require __DIR__ . '/../config/dev-guide-service-examples.php ' ;
488- if (isset ($ serviceExamples [$ service ->name ])) {
546+ // Add Examples section
547+ $ docsServiceId = $ serviceIdMap [$ service ->name ] ?? $ service ->name ;
548+ $ hasNewExamples = isset ($ newExamples [$ docsServiceId ]);
549+ $ hasLegacyExamples = isset ($ legacyExamples [$ service ->name ]);
550+
551+ if ($ hasNewExamples || $ hasLegacyExamples ) {
489552 $ html .= '<h2>Examples</h2> ' ;
490- $ html .= '<p>The following examples demonstrate how to use this service with the AWS SDK for PHP. These code examples are available in the <a href=" ' . $ serviceExamples [$ service ->name ]['landing_page ' ] . '">AWS SDK for PHP Developer Guide</a>.</p> ' ;
491- $ html .= '<ul> ' ;
492- foreach ($ serviceExamples [$ service ->name ]['scenarios ' ] as $ title => $ link ) {
493- $ html .= sprintf ('<li><a href="%s">%s</a></li> ' , $ link , $ title );
553+
554+ if ($ hasNewExamples ) {
555+ $ html .= '<h3>Basics, Actions and Scenarios</h3> ' ;
556+ $ html .= '<p>The following code examples show you how to perform actions and implement common scenarios by using the AWS SDK for PHP with ' . htmlspecialchars ($ service ->title ) . '.</p> ' ;
557+ $ html .= '<ul> ' ;
558+ $ html .= sprintf ('<li><a href="%s">See examples on AWS Docs</a></li> ' , htmlspecialchars ($ newExamples [$ docsServiceId ]));
559+ $ html .= '</ul> ' ;
560+ }
561+
562+ if ($ hasLegacyExamples ) {
563+ $ html .= '<h3>Legacy Code Examples With Guidance</h3> ' ;
564+ $ html .= '<p>The following examples demonstrate how to use this service with the AWS SDK for PHP. These code examples are available in the <a href=" ' . htmlspecialchars ($ legacyExamples [$ service ->name ]['landing_page ' ]) . '">AWS SDK for PHP Developer Guide</a>.</p> ' ;
565+ $ html .= '<ul> ' ;
566+ foreach ($ legacyExamples [$ service ->name ]['scenarios ' ] as $ title => $ link ) {
567+ $ html .= sprintf ('<li><a href="%s">%s</a></li> ' , htmlspecialchars ($ link ), htmlspecialchars ($ title ));
568+ }
569+ $ html .= '</ul> ' ;
494570 }
495- $ html .= '</ul> ' ;
496571 }
497572
498573 $ this ->replaceInner ($ service ->clientLink , $ html , '<!-- api --> ' );
@@ -744,26 +819,26 @@ private function createHtmlForWaiters(HtmlDocument $html, Api $service)
744819 $ html ->section (2 , 'Waiters ' );
745820 $ html ->elem ('p ' , 'phpdocumentor-summary ' , $ desc );
746821 $ html ->open ('table ' , 'table-responsive table-striped ' );
747- $ html ->open ('thead ' );
748- $ html ->open ('tr ' );
749- $ html ->elem ('th ' , null , 'Waiter name ' );
750- $ html ->elem ('th ' , null , 'API Operation ' );
751- $ html ->elem ('th ' , null , 'Delay ' );
752- $ html ->elem ('th ' , null , 'Max Attempts ' );
753- $ html ->close ();
754- $ html ->close ();
755- $ html ->open ('tbody ' );
756- foreach ($ waiters as $ name => $ config ) {
757- $ html ->open ('tr ' );
758- $ html ->elem ('td ' , null , $ name );
759- $ html ->elem ('td ' , null , '<a href="# '
760- . strtolower ($ config ['operation ' ])
761- . '"> ' . $ config ['operation ' ] . '</a> ' );
762- $ html ->elem ('td ' , null , $ config ['delay ' ]);
763- $ html ->elem ('td ' , null , $ config ['maxAttempts ' ]);
764- $ html ->close ();
765- }
822+ $ html ->open ('thead ' );
823+ $ html ->open ('tr ' );
824+ $ html ->elem ('th ' , null , 'Waiter name ' );
825+ $ html ->elem ('th ' , null , 'API Operation ' );
826+ $ html ->elem ('th ' , null , 'Delay ' );
827+ $ html ->elem ('th ' , null , 'Max Attempts ' );
828+ $ html ->close ();
829+ $ html ->close ();
830+ $ html ->open ('tbody ' );
831+ foreach ($ waiters as $ name => $ config ) {
832+ $ html ->open ('tr ' );
833+ $ html ->elem ('td ' , null , $ name );
834+ $ html ->elem ('td ' , null , '<a href="# '
835+ . strtolower ($ config ['operation ' ])
836+ . '"> ' . $ config ['operation ' ] . '</a> ' );
837+ $ html ->elem ('td ' , null , $ config ['delay ' ]);
838+ $ html ->elem ('td ' , null , $ config ['maxAttempts ' ]);
766839 $ html ->close ();
840+ }
841+ $ html ->close ();
767842 $ html ->close ();
768843 }
769844
@@ -787,12 +862,12 @@ private function createHtmlForPaginators(HtmlDocument $html, Api $service)
787862 $ html ->section (2 , 'Paginators ' );
788863 $ html ->elem ('p ' , 'phpdocumentor-summary ' , $ desc );
789864 $ html ->open ('dl ' );
790- foreach ($ paginators as $ name => $ config ) {
791- $ html ->open ('dt ' , 'phpdocumentor-table-of-contents__entry ' );
792- $ attr = ['href ' => '# ' . strtolower ($ name ), 'aria-label ' => strtolower ($ name )];
793- $ html ->elem ('a ' , $ attr , '<strong> ' . $ name . '</strong> ' );
794- $ html ->close ();
795- }
865+ foreach ($ paginators as $ name => $ config ) {
866+ $ html ->open ('dt ' , 'phpdocumentor-table-of-contents__entry ' );
867+ $ attr = ['href ' => '# ' . strtolower ($ name ), 'aria-label ' => strtolower ($ name )];
868+ $ html ->elem ('a ' , $ attr , '<strong> ' . $ name . '</strong> ' );
869+ $ html ->close ();
870+ }
796871 $ html ->close ();
797872 }
798873
@@ -890,15 +965,15 @@ private function createHtmlForOperation(Service $service, $name, Operation $oper
890965 ?: 'This error does not currently have a description. ' ;
891966 $ html
892967 ->open ('dt ' )
893- ->elem (
894- 'a ' ,
895- [
896- 'href ' => $ service ->exceptionLink . '#shape- '
897- . strtolower ($ error ->getName ()),
898- 'aria-label ' => strtolower ($ error ->getName ())
899- ],
900- '<strong> ' . $ error ['name ' ] . ': ' . '</strong> ' )
901- ->elem ('dd ' , 'phpdocumentor-summary ' , $ desc )
968+ ->elem (
969+ 'a ' ,
970+ [
971+ 'href ' => $ service ->exceptionLink . '#shape- '
972+ . strtolower ($ error ->getName ()),
973+ 'aria-label ' => strtolower ($ error ->getName ())
974+ ],
975+ '<strong> ' . $ error ['name ' ] . ': ' . '</strong> ' )
976+ ->elem ('dd ' , 'phpdocumentor-summary ' , $ desc )
902977 ->close ();
903978 }
904979 $ html ->close ();
@@ -920,15 +995,15 @@ private function createHtmlForOperation(Service $service, $name, Operation $oper
920995 }
921996 $ comments = $ example ['comments ' ] ?? [];
922997 $ html ->elem ('pre ' , 'phpdocumentor-code ' , $ generator ->generateInput (
923- $ name ,
924- isset ($ example ['input ' ]) ? $ example ['input ' ] : [],
998+ $ name ,
999+ isset ($ example ['input ' ]) ? $ example ['input ' ] : [],
9251000 isset ($ comments ['input ' ]) ? $ comments ['input ' ] : []
9261001 ));
9271002 if (isset ($ example ['output ' ])) {
9281003 $ html ->elem ('p ' , 'phpdocumentor-summary ' , 'Result syntax: ' );
9291004 $ html ->elem ('pre ' , 'phpdocumentor-code ' , $ generator ->generateOutput (
930- $ name ,
931- $ example ['output ' ],
1005+ $ name ,
1006+ $ example ['output ' ],
9321007 isset ($ comments ['output ' ])
9331008 ? $ comments ['output ' ]
9341009 : []
@@ -966,8 +1041,8 @@ private function logIssues($serviceName, $serviceVersion, $issuesToLog)
9661041 foreach ($ shapeIssues as $ level => $ messages ) {
9671042 foreach ($ messages as $ message => $ exampleName ) {
9681043 $ this ->issues [$ level ][$ serviceName ][$ serviceVersion ][
969- $ exampleName . ' has an issue - '
970- . $ message . ' on ' . $ shapeName
1044+ $ exampleName . ' has an issue - '
1045+ . $ message . ' on ' . $ shapeName
9711046 ] = true ;
9721047 }
9731048 }
@@ -1094,7 +1169,7 @@ function ($carry, $item) {
10941169 private function getDocumentText (StructureShape $ member )
10951170 {
10961171 return 'document (null|bool|string|numeric) or an (array|associative array) '
1097- . ' whose members are all valid documents ' ;
1172+ . ' whose members are all valid documents ' ;
10981173 }
10991174
11001175 private function getPrimitivePhpType ($ member )
0 commit comments