From 98a5817b7eb3364dae87262ca43054d46f8b0035 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Fri, 15 Nov 2024 16:36:53 -0500 Subject: [PATCH 01/29] USAGOV-2073-published-pages: Figure out config setting to get correct breadcrumb to export. --- .../src/TaxonomyDatalayerBuilder.php | 3 +- .../Controller/PublishedPagesController.php | 122 +++++++++++++++++ .../src/Data/PublishedPagesRow.php | 125 ++++++++++++++++++ .../usagov_ssg_postprocessing.routing.yml | 29 ++-- 4 files changed, 269 insertions(+), 10 deletions(-) create mode 100644 web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php create mode 100644 web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php diff --git a/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php b/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php index cce076f5f1..1c5bf55bc3 100644 --- a/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php +++ b/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php @@ -5,6 +5,7 @@ use Drupal\Core\Breadcrumb\BreadcrumbManager; use Drupal\Core\Entity\EntityMalformedException; use Drupal\Core\Routing\CurrentRouteMatch; +use Drupal\Core\Routing\RouteMatchInterface; use Drupal\node\Entity\Node; /** @@ -48,7 +49,7 @@ class TaxonomyDatalayerBuilder { private string $isFront; public function __construct( - private CurrentRouteMatch $routeMatch, + private RouteMatchInterface $routeMatch, private BreadcrumbManager $breadcrumbManager, public Node $node, bool $isFront, diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php new file mode 100644 index 0000000000..a097fcc849 --- /dev/null +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -0,0 +1,122 @@ +getNodeCSV(); + } + + protected function getNodeCSV() { + $nids = $this->entityTypeManager() + ->getStorage('node') + ->getQuery() + ->condition('status', 1) //published +// ->condition('nid', 84) + ->sort('nid', 'ASC') + ->accessCheck(TRUE) + ->sort('nid') + ->range(0, 100) + ->execute(); + + ob_start(); + $out = fopen('php://output', 'w'); + fputcsv($out, $this->CSVHeader); + // TODO handle translated nodes (homepage in spanish) + foreach ($nids as $nid) { + $node = $this->entityTypeManager()->getStorage('node')->load($nid); + $row = $this->getNodeRow($node); + fputcsv($out, $row->toArray()); + } + $content = ob_get_clean(); + fclose($out); + + $response = new Response(); + $response->headers->set('Content-Type', 'text/plain'); + $response->setContent($content); + return $response->send(); + } + + protected function getNodeRow(Node $node): PublishedPagesRow { + $config = \Drupal::config('system.site'); + $front_uri = $config->get('page.front'); + $alias = \Drupal::service('path_alias.manager')->getAliasByPath('/node/' . $node->id()); + + $isFront = ($alias === $front_uri); + + $pageType = NULL; // TODO implement + + // To get the right breadcrumb/active trail for this routeMatch, + // the menu_breadcrumb module must be configured to "Derive MenuActiveTrail from RouteMatch" + // TODO: could we change that config only on this path?? + $datalayer = new TaxonomyDatalayerBuilder( + routeMatch: $this->getRouteMatchForNode($node), + breadcrumbManager: Drupal::service('breadcrumb'), + node: $node, + isFront: $isFront, + basicPagesubType: $pageType ?? NULL, + ); + + $baseURL = \Drupal::request()->getSchemeAndHttpHost(); + return PublishedPagesRow::datalayerForNode($datalayer, $node, $baseURL); + } + + /** + * Get a valid routeMatch object for a node + * + * To get the same datalayer output, we need to set up a routeMatch for each + * entity we are exporting that the datalayer module can lookup via the + * breadcrumb manager. + */ + private function getRouteMatchForNode(Node $node): RouteMatchInterface { + $router = \Drupal::service('router.no_access_checks'); + $route = $router->match('/node/' . $node->id()); + return new RouteMatch( + route_name: $route['_route'], + route: $route['_route_object'], + parameters: ['node' => $node], + raw_parameters: ['node' => $node->id()] + ); + + + } +} diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php new file mode 100644 index 0000000000..406abc03b8 --- /dev/null +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -0,0 +1,125 @@ +hierarchy, + $this->pageType, + $this->pageSubType ?? '', + $this->contentType, + $this->friendlyURL, + $this->pageID, + $this->pageTitle, + $this->fullURL, + $this->TaxonomyText1, + $this->TaxonomyText2, + $this->TaxonomyText3, + $this->TaxonomyText4, + $this->TaxonomyText5, + $this->TaxonomyText6, + $this->TaxonomyURL1, + $this->TaxonomyURL2, + $this->TaxonomyURL3, + $this->TaxonomyURL4, + $this->TaxonomyURL5, + $this->TaxonomyURL6, + $this->isHomePage ? 'homepage' : 'not_homepage', + $this->toggleURL, + ]; + } + + public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node, string $base_url): self { + $data = $dl->build(); + + $hierarchy = 1; + + $friendlyURL = $node->toUrl()->toString(); + $fullURL = $base_url . $node->toUrl()->toString(); + $title = $node->getTitle(); + + $toggleAlias = NULL; + if ($node->field_language_toggle[0]->target_id) { + + $toggleLang = match($node->language()->getId()) { + 'en' => 'es', + 'es' => 'en' + }; + + $toggleAlias = \Drupal::service('path_alias.manager') + ->getAliasByPath('/node/' . $node->field_language_toggle[0]->target_id, $toggleLang); + if ($data['homepageTest'] === 'homepage') { + // TODO figure out linking for homepage + } + } + $toggleURL = $toggleAlias; + +// $toggle_url = $xpath->query('/html/head/link[contains(@data-type, "altlang")]/@href')->item(0)->nodeValue; +// $decoded["Toggle URL"] = ($toggle_url) ? $toggle_url : "None"; + + + return new self( + hierarchy: $hierarchy, + pageType: $data['Page_Type'], + pageSubType: $data['basicPagesubType'], + contentType: $data['contentType'], + friendlyURL: $friendlyURL, + pageID: $data['nodeID'], + pageTitle: $title, + fullURL: $fullURL, + TaxonomyText1: $data['Taxonomy_Text_1'], + TaxonomyText2: $data['Taxonomy_Text_2'], + TaxonomyText3: $data['Taxonomy_Text_3'], + TaxonomyText4: $data['Taxonomy_Text_4'], + TaxonomyText5: $data['Taxonomy_Text_5'], + TaxonomyText6: $data['Taxonomy_Text_6'], + TaxonomyURL1: $data['Taxonomy_URL_1'], + TaxonomyURL2: $data['Taxonomy_URL_2'], + TaxonomyURL3: $data['Taxonomy_URL_3'], + TaxonomyURL4: $data['Taxonomy_URL_4'], + TaxonomyURL5: $data['Taxonomy_URL_5'], + TaxonomyURL6: $data['Taxonomy_URL_6'], + isHomePage: $data['homepageTest'], + toggleURL: $toggleURL ?? '', + ); + } +} diff --git a/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml b/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml index 55363e08b3..942fa6b9e5 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml +++ b/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml @@ -15,21 +15,32 @@ usagov_ssg_postprocessing.toggle_tome: _permission: 'administer site configuration' usagov_ssg_postprocessing.content: - path: '/static-site-status' - defaults: - _controller: '\Drupal\usagov_ssg_postprocessing\Controller\SsgStatController::content' + path: '/static-site-status' + defaults: + _controller: '\Drupal\usagov_ssg_postprocessing\Controller\SsgStatController::content' _title: 'Tome Status' options: no_cache: 'TRUE' - requirements: - _permission: 'access administration pages' + requirements: + _permission: 'access administration pages' usagov_ssg_postprocessing.site_lag_test: - path: '/site-lag-test' - defaults: - _controller: '\Drupal\usagov_ssg_postprocessing\Controller\SsgStatController::siteLagTest' + path: '/site-lag-test' + defaults: + _controller: '\Drupal\usagov_ssg_postprocessing\Controller\SsgStatController::siteLagTest' _title: 'Tome Status' options: no_cache: 'TRUE' - requirements: + requirements: _permission: 'access administration pages' + +usagov_ssg_postprocessing.published_pages_csv: + path: '/published-pages.csv' + defaults: + _controller: '\Drupal\usagov_ssg_postprocessing\Controller\PublishedPagesController::buildCSV' + _title: 'Generate published pages CSV' + options: + no_cache: 'TRUE' + requirements: + _access: 'TRUE' + From b34ee9411c92c59a327516f82807e093b7a08925 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 18 Nov 2024 15:18:46 -0500 Subject: [PATCH 02/29] USAGOV-2073-published-pages: Export page type correctly. Export translated node versions. --- .../Controller/PublishedPagesController.php | 19 ++++++-- .../src/Data/PublishedPagesRow.php | 47 +++++++++++++------ 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index a097fcc849..0ee2545dd1 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -66,6 +66,19 @@ protected function getNodeCSV() { $node = $this->entityTypeManager()->getStorage('node')->load($nid); $row = $this->getNodeRow($node); fputcsv($out, $row->toArray()); + + $origLanguage = $node->language(); + if ($languages = $node->getTranslationLanguages()) { + foreach ($languages as $lang) { + if ($lang->getId() !== $origLanguage->getId()) { + // export translated node + $trNode = $node->getTranslation($lang->getId()); + $trRow = $this->getNodeRow($trNode); + fputcsv($out, $trRow->toArray()); + } + } + } + } $content = ob_get_clean(); fclose($out); @@ -83,10 +96,10 @@ protected function getNodeRow(Node $node): PublishedPagesRow { $isFront = ($alias === $front_uri); - $pageType = NULL; // TODO implement + $pageType = usa_twig_vars_get_page_type($node); - // To get the right breadcrumb/active trail for this routeMatch, - // the menu_breadcrumb module must be configured to "Derive MenuActiveTrail from RouteMatch" + // To get the right breadcrumb/active trail for this routeMatch, the menu_breadcrumb module + // must be configured to "Derive MenuActiveTrail from RouteMatch" // TODO: could we change that config only on this path?? $datalayer = new TaxonomyDatalayerBuilder( routeMatch: $this->getRouteMatchForNode($node), diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index 406abc03b8..ba1304b181 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -2,6 +2,7 @@ namespace Drupal\usagov_ssg_postprocessing\Data; +use Drupal\Core\Url; use Drupal\node\Entity\Node; use Drupal\usa_twig_vars\TaxonomyDatalayerBuilder; @@ -68,34 +69,50 @@ public function toArray(): array { ]; } - public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node, string $base_url): self { + public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node, string $baseURL): self { $data = $dl->build(); - $hierarchy = 1; - - $friendlyURL = $node->toUrl()->toString(); - $fullURL = $base_url . $node->toUrl()->toString(); + if ($data['homepageTest'] === 'homepage') { + $friendlyURL = '/'; + $fullURL = $baseURL . '/'; + } else { + $friendlyURL = $node->toUrl('canonical', + options: ['language' => $node->language()] + )->toString(); + $fullURL = $node->toUrl( + options: ['absolute' => TRUE, 'language' => $node->language()] + )->toString(); + } $title = $node->getTitle(); - $toggleAlias = NULL; + $toggleURL = NULL; if ($node->field_language_toggle[0]->target_id) { + $toggleNode = \Drupal::entityTypeManager() + ->getStorage('node') + ->load($node->field_language_toggle[0]->target_id); + $url = Url::fromRoute( + 'entity.node.canonical', + ['node' => $toggleNode->id()], + ['absolute' => TRUE, 'language' => $toggleNode->language()] + ); + $toggleURL = $url->toString(); - $toggleLang = match($node->language()->getId()) { - 'en' => 'es', - 'es' => 'en' - }; - $toggleAlias = \Drupal::service('path_alias.manager') - ->getAliasByPath('/node/' . $node->field_language_toggle[0]->target_id, $toggleLang); if ($data['homepageTest'] === 'homepage') { // TODO figure out linking for homepage } } - $toggleURL = $toggleAlias; + $taxLevel1 = match($node->language()->getId()) { + 'es' => TaxonomyDatalayerBuilder::HOME_TITLE_ES, + 'en' => TaxonomyDatalayerBuilder::HOME_URL_EN, + default => TaxonomyDatalayerBuilder::HOME_URL_EN, + }; // $toggle_url = $xpath->query('/html/head/link[contains(@data-type, "altlang")]/@href')->item(0)->nodeValue; // $decoded["Toggle URL"] = ($toggle_url) ? $toggle_url : "None"; + $texts = array_filter($data, fn($key) => str_starts_with($key, 'Taxonomy_Text_'), ARRAY_FILTER_USE_KEY); + $hierarchy = count(array_unique($texts)); return new self( hierarchy: $hierarchy, @@ -106,7 +123,7 @@ public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node pageID: $data['nodeID'], pageTitle: $title, fullURL: $fullURL, - TaxonomyText1: $data['Taxonomy_Text_1'], + TaxonomyText1: $taxLevel1, TaxonomyText2: $data['Taxonomy_Text_2'], TaxonomyText3: $data['Taxonomy_Text_3'], TaxonomyText4: $data['Taxonomy_Text_4'], @@ -119,7 +136,7 @@ public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node TaxonomyURL5: $data['Taxonomy_URL_5'], TaxonomyURL6: $data['Taxonomy_URL_6'], isHomePage: $data['homepageTest'], - toggleURL: $toggleURL ?? '', + toggleURL: $toggleURL ?? 'None', ); } } From b717e9fd5660b91d8ed6df15a5862fa896f8f0ff Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Tue, 19 Nov 2024 09:44:33 -0500 Subject: [PATCH 03/29] USAGOV-2073-published-pages: Fix homepage label --- .../Controller/PublishedPagesController.php | 2 +- .../src/Data/PublishedPagesRow.php | 57 +++++++++++-------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index 0ee2545dd1..a4a29d78a3 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -51,7 +51,7 @@ protected function getNodeCSV() { ->getStorage('node') ->getQuery() ->condition('status', 1) //published -// ->condition('nid', 84) + ->condition('nid', 25) ->sort('nid', 'ASC') ->accessCheck(TRUE) ->sort('nid') diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index ba1304b181..777a5091f0 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -37,7 +37,7 @@ public function __construct( public readonly string $TaxonomyURL4, public readonly string $TaxonomyURL5, public readonly string $TaxonomyURL6, - public readonly bool $isHomePage, + public readonly string $isHomePage, // language toggle public readonly string $toggleURL, ) {} @@ -64,7 +64,7 @@ public function toArray(): array { $this->TaxonomyURL4, $this->TaxonomyURL5, $this->TaxonomyURL6, - $this->isHomePage ? 'homepage' : 'not_homepage', + $this->isHomePage, $this->toggleURL, ]; } @@ -72,10 +72,19 @@ public function toArray(): array { public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node, string $baseURL): self { $data = $dl->build(); - if ($data['homepageTest'] === 'homepage') { - $friendlyURL = '/'; - $fullURL = $baseURL . '/'; - } else { + $title = $node->getTitle(); + $texts = array_filter($data, fn($key) => str_starts_with($key, 'Taxonomy_Text_'), ARRAY_FILTER_USE_KEY); + $hierarchy = count(array_unique($texts)); + + if ($data['homepageTest'] === 'homepage' && $data['language'] === 'en') { + $friendlyURL = TaxonomyDatalayerBuilder::HOME_URL_EN; + $fullURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_EN; + } + else if ($data['homepageTest'] === 'homepage' && $data['language'] === 'es') { + $friendlyURL = TaxonomyDatalayerBuilder::HOME_URL_ES; + $fullURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_ES; + } + else { $friendlyURL = $node->toUrl('canonical', options: ['language' => $node->language()] )->toString(); @@ -83,23 +92,26 @@ public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node options: ['absolute' => TRUE, 'language' => $node->language()] )->toString(); } - $title = $node->getTitle(); + $toggleURL = NULL; if ($node->field_language_toggle[0]->target_id) { - $toggleNode = \Drupal::entityTypeManager() - ->getStorage('node') - ->load($node->field_language_toggle[0]->target_id); - $url = Url::fromRoute( - 'entity.node.canonical', - ['node' => $toggleNode->id()], - ['absolute' => TRUE, 'language' => $toggleNode->language()] - ); - $toggleURL = $url->toString(); - - - if ($data['homepageTest'] === 'homepage') { - // TODO figure out linking for homepage + if ($data['homepageTest'] === 'homepage' && $data['language'] === 'en') { + $toggleURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_ES; + } + else if ($data['homepageTest'] === 'homepage' && $data['language'] === 'es') { + $toggleURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_EN; + } + else { + $toggleNode = \Drupal::entityTypeManager() + ->getStorage('node') + ->load($node->field_language_toggle[0]->target_id); + $url = Url::fromRoute( + 'entity.node.canonical', + ['node' => $toggleNode->id()], + ['absolute' => TRUE, 'language' => $toggleNode->language()] + ); + $toggleURL = $url->toString(); } } @@ -108,11 +120,6 @@ public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node 'en' => TaxonomyDatalayerBuilder::HOME_URL_EN, default => TaxonomyDatalayerBuilder::HOME_URL_EN, }; -// $toggle_url = $xpath->query('/html/head/link[contains(@data-type, "altlang")]/@href')->item(0)->nodeValue; -// $decoded["Toggle URL"] = ($toggle_url) ? $toggle_url : "None"; - - $texts = array_filter($data, fn($key) => str_starts_with($key, 'Taxonomy_Text_'), ARRAY_FILTER_USE_KEY); - $hierarchy = count(array_unique($texts)); return new self( hierarchy: $hierarchy, From 0865b741014b018100f4aba39aa23b29f887e340 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Fri, 22 Nov 2024 15:01:52 -0500 Subject: [PATCH 04/29] USAGOV-2073-published-pages: Get Spanish breadcrumbs correctly --- .../usa_twig_vars/src/TaxonomyDatalayerBuilder.php | 3 ++- .../src/Controller/PublishedPagesController.php | 14 +++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php b/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php index 1c5bf55bc3..9f7197ed68 100644 --- a/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php +++ b/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php @@ -152,7 +152,8 @@ public function fromBreadcrumb(): array { break; } - $url = $crumb->getUrl()->toString() ?: $this->node->toUrl()->toString(); + $url = $crumb->getUrl()->setOption('language', $this->node->language())->toString() + ?: $this->node->toUrl()->setOption('language', $this->node->language())->toString(); if ($url === '/es') { $url = self::HOME_URL_ES; diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index a4a29d78a3..2ec4a37f51 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -90,14 +90,21 @@ protected function getNodeCSV() { } protected function getNodeRow(Node $node): PublishedPagesRow { - $config = \Drupal::config('system.site'); - $front_uri = $config->get('page.front'); + $front_uri = $this->config('system.site')->get('page.front'); $alias = \Drupal::service('path_alias.manager')->getAliasByPath('/node/' . $node->id()); $isFront = ($alias === $front_uri); $pageType = usa_twig_vars_get_page_type($node); + // The following is "dragons abound here" but Drupal does not make it possible + // to change the language for building breadcrumbs after a request has started. + $languageManager = \Drupal::service('language_manager'); + $negotiatedProp = new \ReflectionProperty(get_class($languageManager), 'negotiatedLanguages'); + $value = $negotiatedProp->getValue($languageManager); + $value['language_content'] = $node->language(); + $negotiatedProp->setValue($languageManager, $value); + // To get the right breadcrumb/active trail for this routeMatch, the menu_breadcrumb module // must be configured to "Derive MenuActiveTrail from RouteMatch" // TODO: could we change that config only on this path?? @@ -123,11 +130,12 @@ protected function getNodeRow(Node $node): PublishedPagesRow { private function getRouteMatchForNode(Node $node): RouteMatchInterface { $router = \Drupal::service('router.no_access_checks'); $route = $router->match('/node/' . $node->id()); + return new RouteMatch( route_name: $route['_route'], route: $route['_route_object'], parameters: ['node' => $node], - raw_parameters: ['node' => $node->id()] + raw_parameters: ['node' => $node->id(), 'language' => $node->language()->getId()] ); From 3aae86d15381371057de3af5314a5e2bf7d8dd55 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 25 Nov 2024 10:54:17 -0500 Subject: [PATCH 05/29] USAGOV-2073-published-pages: Clean up node csv export, add hasCategories and categories Column --- .../DatalayerAlterSubscriber.php | 7 +++- .../Controller/PublishedPagesController.php | 32 +++++++++++++++---- .../src/Data/PublishedPagesRow.php | 17 ++++++---- .../PublishedPagesSubscriber.php | 4 +-- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php b/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php index 7c7dddfecc..af90c311ac 100644 --- a/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php +++ b/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php @@ -25,7 +25,12 @@ public static function getSubscribedEvents() { * Adds category information to the datalayer. */ public function onDatalayerAlter(DatalayerAlterEvent $event): void { - $node = \Drupal::routeMatch()->getParameter('node'); + + if (!is_numeric($event->datalayer['nodeID'])) { + return; + } + + $node = Node::load($event->datalayer['nodeID']); $event->datalayer['hasBenefitCategory'] = FALSE; if ($node instanceof Node && $node->getType() === 'basic_page') { diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index 2ec4a37f51..a06b4fd20d 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -7,6 +7,7 @@ use Drupal\Core\Routing\RouteMatch; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\node\Entity\Node; +use Drupal\usa_twig_vars\Event\DatalayerAlterEvent; use Drupal\usa_twig_vars\TaxonomyDatalayerBuilder; use Drupal\usagov_ssg_postprocessing\Data\PublishedPagesRow; use Symfony\Component\HttpFoundation\Response; @@ -36,6 +37,8 @@ class PublishedPagesController extends ControllerBase { "Taxonomy URL Level 6", "Homepage?", "Toggle URL", + "Has Benefit Category", + "Categories" ]; public function buildCSV() { @@ -50,18 +53,26 @@ protected function getNodeCSV() { $nids = $this->entityTypeManager() ->getStorage('node') ->getQuery() + ->condition('type', [ + 'basic_page', + 'bears_life_event', + 'directory_record', + 'federal_directory_index', + 'state_directory_record', + 'wizard_step' + ], 'IN') ->condition('status', 1) //published - ->condition('nid', 25) +// ->condition('nid', 83) ->sort('nid', 'ASC') ->accessCheck(TRUE) ->sort('nid') - ->range(0, 100) +// ->range(0, 500) ->execute(); ob_start(); $out = fopen('php://output', 'w'); fputcsv($out, $this->CSVHeader); - // TODO handle translated nodes (homepage in spanish) + foreach ($nids as $nid) { $node = $this->entityTypeManager()->getStorage('node')->load($nid); $row = $this->getNodeRow($node); @@ -74,7 +85,8 @@ protected function getNodeCSV() { // export translated node $trNode = $node->getTranslation($lang->getId()); $trRow = $this->getNodeRow($trNode); - fputcsv($out, $trRow->toArray()); + $fields = array_map(fn($field) => trim($field), $trRow->toArray()); + fputcsv($out, $fields); } } } @@ -116,8 +128,16 @@ protected function getNodeRow(Node $node): PublishedPagesRow { basicPagesubType: $pageType ?? NULL, ); + $data = $datalayer->build(); + + // Let other modules add to the datalayer payload. + $datalayerEvent = new DatalayerAlterEvent($data); + $dispatcher = \Drupal::service('event_dispatcher'); + $dispatcher->dispatch($datalayerEvent, DatalayerAlterEvent::EVENT_NAME); + $data = $datalayerEvent->datalayer; + $baseURL = \Drupal::request()->getSchemeAndHttpHost(); - return PublishedPagesRow::datalayerForNode($datalayer, $node, $baseURL); + return PublishedPagesRow::datalayerForNode($data, $node, $baseURL); } /** @@ -137,7 +157,5 @@ private function getRouteMatchForNode(Node $node): RouteMatchInterface { parameters: ['node' => $node], raw_parameters: ['node' => $node->id(), 'language' => $node->language()->getId()] ); - - } } diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index 777a5091f0..f803ef4a6d 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -4,6 +4,7 @@ use Drupal\Core\Url; use Drupal\node\Entity\Node; +use Drupal\usa_twig_vars\Event\DatalayerAlterEvent; use Drupal\usa_twig_vars\TaxonomyDatalayerBuilder; /** @@ -40,6 +41,8 @@ public function __construct( public readonly string $isHomePage, // language toggle public readonly string $toggleURL, + public readonly string $hasBenefitCategory, + public readonly string $benefitCategories, ) {} public function toArray(): array { @@ -66,12 +69,12 @@ public function toArray(): array { $this->TaxonomyURL6, $this->isHomePage, $this->toggleURL, + $this->hasBenefitCategory, + $this->benefitCategories, ]; } - public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node, string $baseURL): self { - $data = $dl->build(); - + public static function datalayerForNode(array $data, Node $node, string $baseURL): self { $title = $node->getTitle(); $texts = array_filter($data, fn($key) => str_starts_with($key, 'Taxonomy_Text_'), ARRAY_FILTER_USE_KEY); $hierarchy = count(array_unique($texts)); @@ -116,9 +119,9 @@ public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node } $taxLevel1 = match($node->language()->getId()) { - 'es' => TaxonomyDatalayerBuilder::HOME_TITLE_ES, - 'en' => TaxonomyDatalayerBuilder::HOME_URL_EN, - default => TaxonomyDatalayerBuilder::HOME_URL_EN, + 'es' => "USAGov Español", + 'en' => "USAGov English", + default => "USAGov English", }; return new self( @@ -144,6 +147,8 @@ public static function datalayerForNode(TaxonomyDatalayerBuilder $dl, Node $node TaxonomyURL6: $data['Taxonomy_URL_6'], isHomePage: $data['homepageTest'], toggleURL: $toggleURL ?? 'None', + hasBenefitCategory: $data['hasBenefitCategory'] ? '1' : '', + benefitCategories: $data['benefitCategories'] ?: '', ); } } diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/EventSubscriber/PublishedPagesSubscriber.php b/web/modules/custom/usagov_ssg_postprocessing/src/EventSubscriber/PublishedPagesSubscriber.php index cc6ffafa25..ce44e05608 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/EventSubscriber/PublishedPagesSubscriber.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/EventSubscriber/PublishedPagesSubscriber.php @@ -220,8 +220,8 @@ public function modifyHtml(ModifyHtmlEvent $event) { * {@inheritdoc} */ public static function getSubscribedEvents() { - $events[TomeStaticEvents::MODIFY_HTML][] = ['modifyHtml']; - return $events; +// $events[TomeStaticEvents::MODIFY_HTML][] = ['modifyHtml']; +// return $events; } } From 74e0f16030eb5c8ded3a57dbd0283efc5ef3b009 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 25 Nov 2024 16:15:53 -0500 Subject: [PATCH 06/29] USAGOV-2073-published-pages: Basic export of wizard terms. --- .../DatalayerAlterSubscriber.php | 2 +- .../Controller/PublishedPagesController.php | 90 ++++++++++---- .../src/Data/PublishedPagesRow.php | 65 ++++++++-- .../DatalayerAlterSubscriber.php | 95 +-------------- .../usagov_wizard/src/WizardDataLayer.php | 112 ++++++++++++++++++ 5 files changed, 238 insertions(+), 126 deletions(-) create mode 100644 web/modules/custom/usagov_wizard/src/WizardDataLayer.php diff --git a/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php b/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php index af90c311ac..9ec8f030c7 100644 --- a/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php +++ b/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php @@ -26,7 +26,7 @@ public static function getSubscribedEvents() { */ public function onDatalayerAlter(DatalayerAlterEvent $event): void { - if (!is_numeric($event->datalayer['nodeID'])) { + if (!isset($event->datalayer['nodeID']) || !is_numeric($event->datalayer['nodeID'])) { return; } diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index a06b4fd20d..631344e171 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -7,9 +7,11 @@ use Drupal\Core\Routing\RouteMatch; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\node\Entity\Node; +use Drupal\taxonomy\Entity\Term; use Drupal\usa_twig_vars\Event\DatalayerAlterEvent; use Drupal\usa_twig_vars\TaxonomyDatalayerBuilder; use Drupal\usagov_ssg_postprocessing\Data\PublishedPagesRow; +use Drupal\usagov_wizard\WizardDataLayer; use Symfony\Component\HttpFoundation\Response; class PublishedPagesController extends ControllerBase { @@ -42,14 +44,24 @@ class PublishedPagesController extends ControllerBase { ]; public function buildCSV() { - // TODO: HTTP-headers for CSV? + ob_start(); + $out = fopen('php://output', 'w'); + fputcsv($out, $this->CSVHeader); + + //$this->getNodeCSV($out); + $this->getWizardsCSV($out); - // TODO: Output header row - $this->getNodeCSV(); + $content = ob_get_clean(); + fclose($out); + + $response = new Response(); + $response->headers->set('Content-Type', 'text/plain'); + $response->setContent($content); + return $response->send(); } - protected function getNodeCSV() { + protected function getNodeCSV($out): void { $nids = $this->entityTypeManager() ->getStorage('node') ->getQuery() @@ -69,10 +81,6 @@ protected function getNodeCSV() { // ->range(0, 500) ->execute(); - ob_start(); - $out = fopen('php://output', 'w'); - fputcsv($out, $this->CSVHeader); - foreach ($nids as $nid) { $node = $this->entityTypeManager()->getStorage('node')->load($nid); $row = $this->getNodeRow($node); @@ -90,15 +98,28 @@ protected function getNodeCSV() { } } } - } - $content = ob_get_clean(); - fclose($out); + } - $response = new Response(); - $response->headers->set('Content-Type', 'text/plain'); - $response->setContent($content); - return $response->send(); + protected function getWizardsCSV($out): void { + $tids = $this->entityTypeManager() + ->getStorage('taxonomy_term') + ->getQuery() + ->condition('vid','wizard') + ->condition('status', 1) //published + // ->condition('nid', 83) + ->sort('tid', 'ASC') + ->accessCheck(TRUE) + ->sort('tid') + // ->range(0, 500) + ->execute(); + + + foreach ($tids as $tid) { + $wizard = $this->entityTypeManager()->getStorage('taxonomy_term')->load($tid); + $row = $this->getWizardRow($wizard); + fputcsv($out, $row->toArray()); + } } protected function getNodeRow(Node $node): PublishedPagesRow { @@ -119,7 +140,6 @@ protected function getNodeRow(Node $node): PublishedPagesRow { // To get the right breadcrumb/active trail for this routeMatch, the menu_breadcrumb module // must be configured to "Derive MenuActiveTrail from RouteMatch" - // TODO: could we change that config only on this path?? $datalayer = new TaxonomyDatalayerBuilder( routeMatch: $this->getRouteMatchForNode($node), breadcrumbManager: Drupal::service('breadcrumb'), @@ -127,14 +147,10 @@ protected function getNodeRow(Node $node): PublishedPagesRow { isFront: $isFront, basicPagesubType: $pageType ?? NULL, ); - $data = $datalayer->build(); - // Let other modules add to the datalayer payload. - $datalayerEvent = new DatalayerAlterEvent($data); - $dispatcher = \Drupal::service('event_dispatcher'); - $dispatcher->dispatch($datalayerEvent, DatalayerAlterEvent::EVENT_NAME); - $data = $datalayerEvent->datalayer; + $data = $this->alterDatalayer($data); + $baseURL = \Drupal::request()->getSchemeAndHttpHost(); return PublishedPagesRow::datalayerForNode($data, $node, $baseURL); @@ -144,7 +160,7 @@ protected function getNodeRow(Node $node): PublishedPagesRow { * Get a valid routeMatch object for a node * * To get the same datalayer output, we need to set up a routeMatch for each - * entity we are exporting that the datalayer module can lookup via the + * entity we are exporting that the datalayer module can look up via the * breadcrumb manager. */ private function getRouteMatchForNode(Node $node): RouteMatchInterface { @@ -158,4 +174,32 @@ private function getRouteMatchForNode(Node $node): RouteMatchInterface { raw_parameters: ['node' => $node->id(), 'language' => $node->language()->getId()] ); } + + private function getRouteMatchForWizard(Term $term): RouteMatchInterface { + $router = \Drupal::service('router.no_access_checks'); + $route = $router->match('/taxonomy/term/' . $term->id()); + + return new RouteMatch( + route_name: $route['_route'], + route: $route['_route_object'], + parameters: ['taxonomy_term' => $term], + raw_parameters: ['taxonomy_term' => $term->id(), 'language' => $term->language()->getId()] + ); + } + + protected function getWizardRow(Term $wizard): PublishedPagesRow { + $builder = new WizardDataLayer($wizard, $this->entityTypeManager); + $data = $builder->getData([]); + + $baseURL = \Drupal::request()->getSchemeAndHttpHost(); + return PublishedPagesRow::datalayerForWizard($data, $wizard, $baseURL); + } + + private function alterDatalayer(array $data): array { + // Let other modules add to the datalayer payload. + $datalayerEvent = new DatalayerAlterEvent($data); + $dispatcher = \Drupal::service('event_dispatcher'); + $dispatcher->dispatch($datalayerEvent, DatalayerAlterEvent::EVENT_NAME); + return $datalayerEvent->datalayer; + } } diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index f803ef4a6d..ae284db7de 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -2,8 +2,10 @@ namespace Drupal\usagov_ssg_postprocessing\Data; +use Drupal\Core\Language\Language; use Drupal\Core\Url; use Drupal\node\Entity\Node; +use Drupal\taxonomy\Entity\Term; use Drupal\usa_twig_vars\Event\DatalayerAlterEvent; use Drupal\usa_twig_vars\TaxonomyDatalayerBuilder; @@ -45,6 +47,19 @@ public function __construct( public readonly string $benefitCategories, ) {} + private static function getTaxLevel1(Language $language): string { + return match ($language->getId()) { + 'es' => "USAGov Español", + 'en' => "USAGov English", + default => "USAGov English", + }; + } + + private static function getHierarchy(array $data): int { + $texts = array_filter($data, fn($key) => str_starts_with($key, 'Taxonomy_Text_'), ARRAY_FILTER_USE_KEY); + return count(array_unique($texts)); + } + public function toArray(): array { return [ $this->hierarchy, @@ -76,8 +91,6 @@ public function toArray(): array { public static function datalayerForNode(array $data, Node $node, string $baseURL): self { $title = $node->getTitle(); - $texts = array_filter($data, fn($key) => str_starts_with($key, 'Taxonomy_Text_'), ARRAY_FILTER_USE_KEY); - $hierarchy = count(array_unique($texts)); if ($data['homepageTest'] === 'homepage' && $data['language'] === 'en') { $friendlyURL = TaxonomyDatalayerBuilder::HOME_URL_EN; @@ -118,14 +131,8 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL } } - $taxLevel1 = match($node->language()->getId()) { - 'es' => "USAGov Español", - 'en' => "USAGov English", - default => "USAGov English", - }; - return new self( - hierarchy: $hierarchy, + hierarchy: self::getHierarchy($data), pageType: $data['Page_Type'], pageSubType: $data['basicPagesubType'], contentType: $data['contentType'], @@ -133,7 +140,7 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL pageID: $data['nodeID'], pageTitle: $title, fullURL: $fullURL, - TaxonomyText1: $taxLevel1, + TaxonomyText1: self::getTaxLevel1($node->language()), TaxonomyText2: $data['Taxonomy_Text_2'], TaxonomyText3: $data['Taxonomy_Text_3'], TaxonomyText4: $data['Taxonomy_Text_4'], @@ -151,4 +158,42 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL benefitCategories: $data['benefitCategories'] ?: '', ); } + + public static function datalayerForWizard(array $data, Term $term, string $baseURL): self { + $title = $term->getName(); + + $friendlyURL = $term->toUrl('canonical', + options: ['language' => $term->language()] + )->toString(); + $fullURL = $term->toUrl( + options: ['absolute' => TRUE, 'language' => $term->language()] + )->toString(); + + return new self( + hierarchy: self::getHierarchy($data), + pageType: $data['Page_Type'], + pageSubType: $data['basicPagesubType'], + contentType: $data['contentType'], + friendlyURL: $friendlyURL, + pageID: 't_' . $data['taxonomyID'], + pageTitle: $title, + fullURL: $fullURL, + TaxonomyText1: self::getTaxLevel1($term->language()), + TaxonomyText2: $data['Taxonomy_Text_2'], + TaxonomyText3: $data['Taxonomy_Text_3'], + TaxonomyText4: $data['Taxonomy_Text_4'], + TaxonomyText5: $data['Taxonomy_Text_5'], + TaxonomyText6: $data['Taxonomy_Text_6'], + TaxonomyURL1: $data['Taxonomy_URL_1'], + TaxonomyURL2: $data['Taxonomy_URL_2'], + TaxonomyURL3: $data['Taxonomy_URL_3'], + TaxonomyURL4: $data['Taxonomy_URL_4'], + TaxonomyURL5: $data['Taxonomy_URL_5'], + TaxonomyURL6: $data['Taxonomy_URL_6'], + isHomePage: $data['homepageTest'], + toggleURL: 'None', + hasBenefitCategory: $data['hasBenefitCategory'] ? '1' : '', + benefitCategories: $data['benefitCategories'] ?: '', + ); + } } diff --git a/web/modules/custom/usagov_wizard/src/EventSubscriber/DatalayerAlterSubscriber.php b/web/modules/custom/usagov_wizard/src/EventSubscriber/DatalayerAlterSubscriber.php index 8210c7f883..ae2e0db239 100644 --- a/web/modules/custom/usagov_wizard/src/EventSubscriber/DatalayerAlterSubscriber.php +++ b/web/modules/custom/usagov_wizard/src/EventSubscriber/DatalayerAlterSubscriber.php @@ -9,6 +9,7 @@ use Drupal\taxonomy\Entity\Term; use Drupal\usa_twig_vars\Event\DatalayerAlterEvent; use Drupal\usagov_wizard\MenuChecker; +use Drupal\usagov_wizard\WizardDataLayer; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -41,97 +42,7 @@ public function onDatalayerAlter(DatalayerAlterEvent $event): void { return; } - $termStorage = $this->entityTypeManager->getStorage('taxonomy_term'); - - $isStartPage = FALSE; - $children = $termStorage->loadChildren($term->id()); - $isResult = empty($children); - - if ($term->hasField('parent')) { - $parentTID = $term->parent->getValue()[0]['target_id']; - if ($parentTID === '0') { - $isStartPage = TRUE; - } - } - - if ($isStartPage) { - $page_type = 'wizard-start'; - } - elseif ($isResult) { - $page_type = 'wizard-result'; - } - else { - $page_type = 'wizard-question'; - } - - // keep the same order - unset($event->datalayer['hasBenefitCategory']); - // make any changes need to $event->datalayer array - $event->datalayer['taxonomyID'] = $term->id(); - $event->datalayer['contentType'] = $term->bundle(); - $event->datalayer['language'] = $term->language()->getId(); - $event->datalayer['homepageTest'] = 'not_homepage'; - $event->datalayer['basicPagesubType'] = NULL; - $event->datalayer['Page_Type'] = $page_type; - $event->datalayer['hasBenefitCategory'] = FALSE; - - $rootTerm = NULL; - $parents = []; - if ($term->hasField('parent') && !$term->get('parent')->isEmpty()) { - $parents = $this->entityTypeManager - ->getStorage('taxonomy_term') - ->loadAllParents($term->id()); - // Sort parents so "oldest ancestor" is first. - $parents = array_reverse($parents); - $rootTerm = $parents[array_key_first($parents)]; - } - - if ($rootTerm) { - $crumbs = usagov_wizard_get_term_breadcrumb($rootTerm); - // Here the first two items will give us the home page - // and the main scam page - $crumbs = array_slice($crumbs, 0, 2); - foreach ($crumbs as $crumb) { - $data[$crumb['url']] = $crumb['text']; - } - } - - // the rest comes from the parents of this term - foreach ($parents as $parentTerm) { - $path = $parentTerm->get('path'); - $termURL = $path->alias; - // pathalias field items don't prepend the language code for Spanish terms - if ($parentTerm->language()->getId() === 'es') { - $termURL = '/es' . $termURL; - } - $data[$termURL] = $parentTerm->getName(); - } - - $count = count($data); - - $i = 0; - foreach ($data as $url => $text) { - $i++; - $urls['Taxonomy_Text_' . $i] = $text; - $urls['Taxonomy_URL_' . $i] = $url; - - if ($i === 6) { - break; - } - } - - if ($i < 6) { - $lastURL = array_key_last($data); - $lastText = $data[$lastURL]; - - for ($i = $count; $i < 6; $i++) { - $urls['Taxonomy_Text_' . ($i + 1)] = $lastText; - $urls['Taxonomy_URL_' . ($i + 1)] = $lastURL; - } - } - - ksort($urls); - $event->datalayer = array_merge($event->datalayer, $urls); + $builder = new WizardDataLayer($term, $this->entityTypeManager); + $event->datalayer = $builder->getData($event->datalayer); } - } diff --git a/web/modules/custom/usagov_wizard/src/WizardDataLayer.php b/web/modules/custom/usagov_wizard/src/WizardDataLayer.php new file mode 100644 index 0000000000..acc8180d4a --- /dev/null +++ b/web/modules/custom/usagov_wizard/src/WizardDataLayer.php @@ -0,0 +1,112 @@ +typeManager->getStorage('taxonomy_term'); + + $isStartPage = FALSE; + $children = $termStorage->loadChildren($this->term->id()); + $isResult = empty($children); + + if ($this->term->hasField('parent')) { + $parentTID = $this->term->parent->getValue()[0]['target_id']; + if ($parentTID === '0') { + $isStartPage = TRUE; + } + } + + if ($isStartPage) { + $page_type = 'wizard-start'; + } + elseif ($isResult) { + $page_type = 'wizard-result'; + } + else { + $page_type = 'wizard-question'; + } + + // keep the same order + unset($data['hasBenefitCategory']); + // make any changes need to $event->datalayer array + $data['taxonomyID'] = $this->term->id(); + $data['contentType'] = $this->term->bundle(); + $data['language'] = $this->term->language()->getId(); + $data['homepageTest'] = 'not_homepage'; + $data['basicPagesubType'] = NULL; + $data['Page_Type'] = $page_type; + $data['hasBenefitCategory'] = FALSE; + + $rootTerm = NULL; + $parents = []; + if ( + $this->term->hasField('parent') + && !$this->term->get('parent')->isEmpty() + ) { + $parents = $this->typeManager + ->getStorage('taxonomy_term') + ->loadAllParents($this->term->id()); + // Sort parents so "oldest ancestor" is first. + $parents = array_reverse($parents); + $rootTerm = $parents[array_key_first($parents)]; + } + + if ($rootTerm) { + $crumbs = usagov_wizard_get_term_breadcrumb($rootTerm); + // Here the first two items will give us the home page + // and the main scam page + $crumbs = array_slice($crumbs, 0, 2); + foreach ($crumbs as $crumb) { + $raw[$crumb['url']] = $crumb['text']; + } + } + + // the rest comes from the parents of this term + foreach ($parents as $parentTerm) { + $path = $parentTerm->get('path'); + $termURL = $path->alias; + // pathalias field items don't prepend the language code for Spanish terms + if ($parentTerm->language()->getId() === 'es') { + $termURL = '/es' . $termURL; + } + $raw[$termURL] = $parentTerm->getName(); + } + + $count = count($raw); + + $i = 0; + foreach ($raw as $url => $text) { + $i++; + $urls['Taxonomy_Text_' . $i] = $text; + $urls['Taxonomy_URL_' . $i] = $url; + + if ($i === 6) { + break; + } + } + + if ($i < 6) { + $lastURL = array_key_last($raw); + $lastText = $raw[$lastURL]; + + for ($i = $count; $i < 6; $i++) { + $urls['Taxonomy_Text_' . ($i + 1)] = $lastText; + $urls['Taxonomy_URL_' . ($i + 1)] = $lastURL; + } + } + + ksort($urls); + return array_merge($data, $urls); + } +} From 442987b04219bad34b9da4c75d44709706529afe Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 25 Nov 2024 16:48:48 -0500 Subject: [PATCH 07/29] USAGOV-2073-published-pages: Trim whitespace --- .../src/Controller/PublishedPagesController.php | 11 ++++++----- .../src/Data/PublishedPagesRow.php | 12 ++++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index 631344e171..35c6e6637f 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -48,10 +48,9 @@ public function buildCSV() { $out = fopen('php://output', 'w'); fputcsv($out, $this->CSVHeader); - //$this->getNodeCSV($out); + $this->getNodeCSV($out); $this->getWizardsCSV($out); - $content = ob_get_clean(); fclose($out); @@ -74,7 +73,7 @@ protected function getNodeCSV($out): void { 'wizard_step' ], 'IN') ->condition('status', 1) //published -// ->condition('nid', 83) +// ->condition('nid', 80) ->sort('nid', 'ASC') ->accessCheck(TRUE) ->sort('nid') @@ -83,8 +82,10 @@ protected function getNodeCSV($out): void { foreach ($nids as $nid) { $node = $this->entityTypeManager()->getStorage('node')->load($nid); - $row = $this->getNodeRow($node); - fputcsv($out, $row->toArray()); + $row = $this->getNodeRow($node)->toArray(); + + $row = array_map(fn($col) => trim($col), $row); + fputcsv($out, $row); $origLanguage = $node->language(); if ($languages = $node->getTranslationLanguages()) { diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index ae284db7de..c867e39516 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -6,7 +6,6 @@ use Drupal\Core\Url; use Drupal\node\Entity\Node; use Drupal\taxonomy\Entity\Term; -use Drupal\usa_twig_vars\Event\DatalayerAlterEvent; use Drupal\usa_twig_vars\TaxonomyDatalayerBuilder; /** @@ -56,12 +55,12 @@ private static function getTaxLevel1(Language $language): string { } private static function getHierarchy(array $data): int { - $texts = array_filter($data, fn($key) => str_starts_with($key, 'Taxonomy_Text_'), ARRAY_FILTER_USE_KEY); + $texts = array_filter($data, fn($key) => str_starts_with($key, 'Taxonomy_URL_'), ARRAY_FILTER_USE_KEY); return count(array_unique($texts)); } public function toArray(): array { - return [ + $array = [ $this->hierarchy, $this->pageType, $this->pageSubType ?? '', @@ -85,8 +84,13 @@ public function toArray(): array { $this->isHomePage, $this->toggleURL, $this->hasBenefitCategory, - $this->benefitCategories, ]; + + // Keeps existing behavior of only including these columns if they have something + if ($this->hasBenefitCategory !== "") { + $array[] = $this->benefitCategories; + } + return $array; } public static function datalayerForNode(array $data, Node $node, string $baseURL): self { From 301a5cf6a41d89452f5a960a53d221f84e5d0570 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Tue, 26 Nov 2024 10:03:22 -0500 Subject: [PATCH 08/29] USAGOV-2073-published-pages: Fix links in Spanish wizards. --- .../src/Controller/PublishedPagesController.php | 2 +- web/modules/custom/usagov_wizard/usagov_wizard.module | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index 35c6e6637f..ebc79a4677 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -108,7 +108,7 @@ protected function getWizardsCSV($out): void { ->getQuery() ->condition('vid','wizard') ->condition('status', 1) //published - // ->condition('nid', 83) +// ->condition('tid', 63) ->sort('tid', 'ASC') ->accessCheck(TRUE) ->sort('tid') diff --git a/web/modules/custom/usagov_wizard/usagov_wizard.module b/web/modules/custom/usagov_wizard/usagov_wizard.module index 643ee27eb5..46e2877ac2 100644 --- a/web/modules/custom/usagov_wizard/usagov_wizard.module +++ b/web/modules/custom/usagov_wizard/usagov_wizard.module @@ -393,6 +393,10 @@ function usagov_wizard_get_term_breadcrumb(Term $rootTerm): array { foreach ($crumbs as $crumb) { if (isset($crumb['uri'])) { $crumb['url'] = Url::fromUri($crumb['uri'])->toString(); + // Sometimes Drupal doesn't prepend Spanish path prefix. + if ($rootTerm->language()->getId() === 'es' && !str_starts_with($crumb['url'], '/es/')) { + $crumb['url'] = '/es' . $crumb['url']; + } } if (isset($crumb['title'])) { $crumb['text'] = ($crumb['title']); From 751ba00282d15543384dee93c1aa993eb6bc78bb Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Tue, 26 Nov 2024 11:07:58 -0500 Subject: [PATCH 09/29] USAGOV-2073-published-pages: Add language toggle URL to wizard columns --- .../src/Controller/PublishedPagesController.php | 10 +++++----- .../src/Data/PublishedPagesRow.php | 14 +++++++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index ebc79a4677..147813ef82 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -39,21 +39,21 @@ class PublishedPagesController extends ControllerBase { "Taxonomy URL Level 6", "Homepage?", "Toggle URL", - "Has Benefit Category", + "hasBenefitCategory", "Categories" ]; public function buildCSV() { - + // Set up to echo CSV rows to STDOUT/browser. ob_start(); $out = fopen('php://output', 'w'); fputcsv($out, $this->CSVHeader); - + // Render published pages to output stream $this->getNodeCSV($out); $this->getWizardsCSV($out); - + // Write contents to output stream $content = ob_get_clean(); fclose($out); - + // Output CSV response $response = new Response(); $response->headers->set('Content-Type', 'text/plain'); $response->setContent($content); diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index c867e39516..bc3886f323 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -173,6 +173,18 @@ public static function datalayerForWizard(array $data, Term $term, string $baseU options: ['absolute' => TRUE, 'language' => $term->language()] )->toString(); + $toggleURL = 'None'; + if (isset($term->field_language_toggle[0])) { + $toggleTerm = \Drupal::entityTypeManager() + ->getStorage('taxonomy_term') + ->load($term->field_language_toggle[0]->target_id); + $url = Url::fromRoute( + 'entity.taxonomy_term.canonical', + ['taxonomy_term' => $toggleTerm->id()], + ['absolute' => TRUE, 'language' => $toggleTerm->language()] + ); + $toggleURL = $url->toString(); + } return new self( hierarchy: self::getHierarchy($data), pageType: $data['Page_Type'], @@ -195,7 +207,7 @@ public static function datalayerForWizard(array $data, Term $term, string $baseU TaxonomyURL5: $data['Taxonomy_URL_5'], TaxonomyURL6: $data['Taxonomy_URL_6'], isHomePage: $data['homepageTest'], - toggleURL: 'None', + toggleURL: $toggleURL, hasBenefitCategory: $data['hasBenefitCategory'] ? '1' : '', benefitCategories: $data['benefitCategories'] ?: '', ); From 5e28761493487cb579fa9ad7fcc381d374e23c7e Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Wed, 4 Dec 2024 14:06:58 -0500 Subject: [PATCH 10/29] USAGOV-2073-published-pages: Moves to use dependency injection for services and cleans up code style. --- .../src/TaxonomyDatalayerBuilder.php | 1 - .../Controller/PublishedPagesController.php | 89 +++--- .../src/Data/PublishedPagesRow.php | 105 +++---- .../PublishedPagesSubscriber.php | 259 ------------------ .../usagov_ssg_postprocessing.routing.yml | 7 +- .../usagov_ssg_postprocessing.services.yml | 4 - .../DatalayerAlterSubscriber.php | 3 +- .../usagov_wizard/src/WizardDataLayer.php | 1 + 8 files changed, 107 insertions(+), 362 deletions(-) delete mode 100644 web/modules/custom/usagov_ssg_postprocessing/src/EventSubscriber/PublishedPagesSubscriber.php diff --git a/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php b/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php index 9f7197ed68..264cb50d86 100644 --- a/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php +++ b/web/modules/custom/usa_twig_vars/src/TaxonomyDatalayerBuilder.php @@ -4,7 +4,6 @@ use Drupal\Core\Breadcrumb\BreadcrumbManager; use Drupal\Core\Entity\EntityMalformedException; -use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\node\Entity\Node; diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index 147813ef82..32ce3be39e 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -2,21 +2,25 @@ namespace Drupal\usagov_ssg_postprocessing\Controller; -use Drupal; +use Drupal\Core\Breadcrumb\BreadcrumbManager; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Routing\RouteMatch; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Routing\Router; use Drupal\node\Entity\Node; +use Drupal\path_alias\AliasManagerInterface; use Drupal\taxonomy\Entity\Term; use Drupal\usa_twig_vars\Event\DatalayerAlterEvent; use Drupal\usa_twig_vars\TaxonomyDatalayerBuilder; use Drupal\usagov_ssg_postprocessing\Data\PublishedPagesRow; use Drupal\usagov_wizard\WizardDataLayer; -use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\Request; class PublishedPagesController extends ControllerBase { - private array $CSVHeader = [ + private array $csvHeader = [ "Hierarchy Level", "Page Type", "Page Sub Type", @@ -40,16 +44,40 @@ class PublishedPagesController extends ControllerBase { "Homepage?", "Toggle URL", "hasBenefitCategory", - "Categories" + "Categories", ]; - public function buildCSV() { + + public function __construct( + private EventDispatcherInterface $dispatcher, + private Request $request, + private Router $router, + private AliasManagerInterface $pathAliasManager, + private BreadcrumbManager $breadcrumb, + ) {} + + /** + * {@inheritdoc} + * + * @return static + */ + public static function create(ContainerInterface $container) { + return new static( + dispatcher: $container->get('event_dispatcher'), + request: $container->get('request_stack')->getCurrentRequest(), + router: $container->get('router.no_access_checks'), + pathAliasManager: $container->get('path_alias.manager'), + breadcrumb: $container->get('breadcrumb'), + ); + } + + public function buildFile() { // Set up to echo CSV rows to STDOUT/browser. ob_start(); $out = fopen('php://output', 'w'); - fputcsv($out, $this->CSVHeader); + fputcsv($out, $this->csvHeader); // Render published pages to output stream - $this->getNodeCSV($out); - $this->getWizardsCSV($out); + $this->saveNodeRows($out); + $this->saveWizardRows($out); // Write contents to output stream $content = ob_get_clean(); fclose($out); @@ -60,7 +88,7 @@ public function buildCSV() { return $response->send(); } - protected function getNodeCSV($out): void { + protected function saveNodeRows($out): void { $nids = $this->entityTypeManager() ->getStorage('node') ->getQuery() @@ -70,14 +98,12 @@ protected function getNodeCSV($out): void { 'directory_record', 'federal_directory_index', 'state_directory_record', - 'wizard_step' + 'wizard_step', ], 'IN') ->condition('status', 1) //published -// ->condition('nid', 80) ->sort('nid', 'ASC') ->accessCheck(TRUE) ->sort('nid') -// ->range(0, 500) ->execute(); foreach ($nids as $nid) { @@ -102,20 +128,17 @@ protected function getNodeCSV($out): void { } } - protected function getWizardsCSV($out): void { + protected function saveWizardRows($out): void { $tids = $this->entityTypeManager() ->getStorage('taxonomy_term') ->getQuery() - ->condition('vid','wizard') + ->condition('vid', 'wizard') ->condition('status', 1) //published -// ->condition('tid', 63) ->sort('tid', 'ASC') ->accessCheck(TRUE) ->sort('tid') - // ->range(0, 500) ->execute(); - foreach ($tids as $tid) { $wizard = $this->entityTypeManager()->getStorage('taxonomy_term')->load($tid); $row = $this->getWizardRow($wizard); @@ -125,25 +148,25 @@ protected function getWizardsCSV($out): void { protected function getNodeRow(Node $node): PublishedPagesRow { $front_uri = $this->config('system.site')->get('page.front'); - $alias = \Drupal::service('path_alias.manager')->getAliasByPath('/node/' . $node->id()); + $alias = $this->pathAliasManager->getAliasByPath('/node/' . $node->id()); $isFront = ($alias === $front_uri); $pageType = usa_twig_vars_get_page_type($node); + $languageManager = $this->languageManager(); // The following is "dragons abound here" but Drupal does not make it possible // to change the language for building breadcrumbs after a request has started. - $languageManager = \Drupal::service('language_manager'); $negotiatedProp = new \ReflectionProperty(get_class($languageManager), 'negotiatedLanguages'); $value = $negotiatedProp->getValue($languageManager); $value['language_content'] = $node->language(); - $negotiatedProp->setValue($languageManager, $value); + $negotiatedProp->setValue($this->languageManager, $value); // To get the right breadcrumb/active trail for this routeMatch, the menu_breadcrumb module // must be configured to "Derive MenuActiveTrail from RouteMatch" $datalayer = new TaxonomyDatalayerBuilder( routeMatch: $this->getRouteMatchForNode($node), - breadcrumbManager: Drupal::service('breadcrumb'), + breadcrumbManager: $this->breadcrumb, node: $node, isFront: $isFront, basicPagesubType: $pageType ?? NULL, @@ -152,8 +175,7 @@ protected function getNodeRow(Node $node): PublishedPagesRow { $data = $this->alterDatalayer($data); - - $baseURL = \Drupal::request()->getSchemeAndHttpHost(); + $baseURL = $this->request->getSchemeAndHttpHost(); return PublishedPagesRow::datalayerForNode($data, $node, $baseURL); } @@ -165,8 +187,7 @@ protected function getNodeRow(Node $node): PublishedPagesRow { * breadcrumb manager. */ private function getRouteMatchForNode(Node $node): RouteMatchInterface { - $router = \Drupal::service('router.no_access_checks'); - $route = $router->match('/node/' . $node->id()); + $route = $this->router->match('/node/' . $node->id()); return new RouteMatch( route_name: $route['_route'], @@ -176,31 +197,19 @@ private function getRouteMatchForNode(Node $node): RouteMatchInterface { ); } - private function getRouteMatchForWizard(Term $term): RouteMatchInterface { - $router = \Drupal::service('router.no_access_checks'); - $route = $router->match('/taxonomy/term/' . $term->id()); - - return new RouteMatch( - route_name: $route['_route'], - route: $route['_route_object'], - parameters: ['taxonomy_term' => $term], - raw_parameters: ['taxonomy_term' => $term->id(), 'language' => $term->language()->getId()] - ); - } - protected function getWizardRow(Term $wizard): PublishedPagesRow { $builder = new WizardDataLayer($wizard, $this->entityTypeManager); $data = $builder->getData([]); - $baseURL = \Drupal::request()->getSchemeAndHttpHost(); + $baseURL = $this->request->getSchemeAndHttpHost(); return PublishedPagesRow::datalayerForWizard($data, $wizard, $baseURL); } private function alterDatalayer(array $data): array { // Let other modules add to the datalayer payload. $datalayerEvent = new DatalayerAlterEvent($data); - $dispatcher = \Drupal::service('event_dispatcher'); - $dispatcher->dispatch($datalayerEvent, DatalayerAlterEvent::EVENT_NAME); + $this->dispatcher->dispatch($datalayerEvent, DatalayerAlterEvent::EVENT_NAME); return $datalayerEvent->datalayer; } + } diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index bc3886f323..4aff1e36ad 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -12,6 +12,7 @@ * Data structure describing the columns of the Published Pages CSV */ final class PublishedPagesRow { + public function __construct( // depths in menu tree public readonly int $hierarchy, @@ -27,18 +28,18 @@ public function __construct( public readonly string $pageTitle, // complete URL including domain name public readonly string $fullURL, - public readonly string $TaxonomyText1, - public readonly string $TaxonomyText2, - public readonly string $TaxonomyText3, - public readonly string $TaxonomyText4, - public readonly string $TaxonomyText5, - public readonly string $TaxonomyText6, - public readonly string $TaxonomyURL1, - public readonly string $TaxonomyURL2, - public readonly string $TaxonomyURL3, - public readonly string $TaxonomyURL4, - public readonly string $TaxonomyURL5, - public readonly string $TaxonomyURL6, + public readonly string $taxonomyText1, + public readonly string $taxonomyText2, + public readonly string $taxonomyText3, + public readonly string $taxonomyText4, + public readonly string $taxonomyText5, + public readonly string $taxonomyText6, + public readonly string $taxonomyURL1, + public readonly string $taxonomyURL2, + public readonly string $taxonomyURL3, + public readonly string $taxonomyURL4, + public readonly string $taxonomyURL5, + public readonly string $taxonomyURL6, public readonly string $isHomePage, // language toggle public readonly string $toggleURL, @@ -69,18 +70,18 @@ public function toArray(): array { $this->pageID, $this->pageTitle, $this->fullURL, - $this->TaxonomyText1, - $this->TaxonomyText2, - $this->TaxonomyText3, - $this->TaxonomyText4, - $this->TaxonomyText5, - $this->TaxonomyText6, - $this->TaxonomyURL1, - $this->TaxonomyURL2, - $this->TaxonomyURL3, - $this->TaxonomyURL4, - $this->TaxonomyURL5, - $this->TaxonomyURL6, + $this->taxonomyText1, + $this->taxonomyText2, + $this->taxonomyText3, + $this->taxonomyText4, + $this->taxonomyText5, + $this->taxonomyText6, + $this->taxonomyURL1, + $this->taxonomyURL2, + $this->taxonomyURL3, + $this->taxonomyURL4, + $this->taxonomyURL5, + $this->taxonomyURL6, $this->isHomePage, $this->toggleURL, $this->hasBenefitCategory, @@ -100,7 +101,7 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL $friendlyURL = TaxonomyDatalayerBuilder::HOME_URL_EN; $fullURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_EN; } - else if ($data['homepageTest'] === 'homepage' && $data['language'] === 'es') { + elseif ($data['homepageTest'] === 'homepage' && $data['language'] === 'es') { $friendlyURL = TaxonomyDatalayerBuilder::HOME_URL_ES; $fullURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_ES; } @@ -113,13 +114,12 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL )->toString(); } - $toggleURL = NULL; if ($node->field_language_toggle[0]->target_id) { if ($data['homepageTest'] === 'homepage' && $data['language'] === 'en') { $toggleURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_ES; } - else if ($data['homepageTest'] === 'homepage' && $data['language'] === 'es') { + elseif ($data['homepageTest'] === 'homepage' && $data['language'] === 'es') { $toggleURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_EN; } else { @@ -144,18 +144,18 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL pageID: $data['nodeID'], pageTitle: $title, fullURL: $fullURL, - TaxonomyText1: self::getTaxLevel1($node->language()), - TaxonomyText2: $data['Taxonomy_Text_2'], - TaxonomyText3: $data['Taxonomy_Text_3'], - TaxonomyText4: $data['Taxonomy_Text_4'], - TaxonomyText5: $data['Taxonomy_Text_5'], - TaxonomyText6: $data['Taxonomy_Text_6'], - TaxonomyURL1: $data['Taxonomy_URL_1'], - TaxonomyURL2: $data['Taxonomy_URL_2'], - TaxonomyURL3: $data['Taxonomy_URL_3'], - TaxonomyURL4: $data['Taxonomy_URL_4'], - TaxonomyURL5: $data['Taxonomy_URL_5'], - TaxonomyURL6: $data['Taxonomy_URL_6'], + taxonomyText1: self::getTaxLevel1($node->language()), + taxonomyText2: $data['Taxonomy_Text_2'], + taxonomyText3: $data['Taxonomy_Text_3'], + taxonomyText4: $data['Taxonomy_Text_4'], + taxonomyText5: $data['Taxonomy_Text_5'], + taxonomyText6: $data['Taxonomy_Text_6'], + taxonomyURL1: $data['Taxonomy_URL_1'], + taxonomyURL2: $data['Taxonomy_URL_2'], + taxonomyURL3: $data['Taxonomy_URL_3'], + taxonomyURL4: $data['Taxonomy_URL_4'], + taxonomyURL5: $data['Taxonomy_URL_5'], + taxonomyURL6: $data['Taxonomy_URL_6'], isHomePage: $data['homepageTest'], toggleURL: $toggleURL ?? 'None', hasBenefitCategory: $data['hasBenefitCategory'] ? '1' : '', @@ -164,7 +164,7 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL } public static function datalayerForWizard(array $data, Term $term, string $baseURL): self { - $title = $term->getName(); + $title = $term->getName(); $friendlyURL = $term->toUrl('canonical', options: ['language' => $term->language()] @@ -194,22 +194,23 @@ public static function datalayerForWizard(array $data, Term $term, string $baseU pageID: 't_' . $data['taxonomyID'], pageTitle: $title, fullURL: $fullURL, - TaxonomyText1: self::getTaxLevel1($term->language()), - TaxonomyText2: $data['Taxonomy_Text_2'], - TaxonomyText3: $data['Taxonomy_Text_3'], - TaxonomyText4: $data['Taxonomy_Text_4'], - TaxonomyText5: $data['Taxonomy_Text_5'], - TaxonomyText6: $data['Taxonomy_Text_6'], - TaxonomyURL1: $data['Taxonomy_URL_1'], - TaxonomyURL2: $data['Taxonomy_URL_2'], - TaxonomyURL3: $data['Taxonomy_URL_3'], - TaxonomyURL4: $data['Taxonomy_URL_4'], - TaxonomyURL5: $data['Taxonomy_URL_5'], - TaxonomyURL6: $data['Taxonomy_URL_6'], + taxonomyText1: self::getTaxLevel1($term->language()), + taxonomyText2: $data['Taxonomy_Text_2'], + taxonomyText3: $data['Taxonomy_Text_3'], + taxonomyText4: $data['Taxonomy_Text_4'], + taxonomyText5: $data['Taxonomy_Text_5'], + taxonomyText6: $data['Taxonomy_Text_6'], + taxonomyURL1: $data['Taxonomy_URL_1'], + taxonomyURL2: $data['Taxonomy_URL_2'], + taxonomyURL3: $data['Taxonomy_URL_3'], + taxonomyURL4: $data['Taxonomy_URL_4'], + taxonomyURL5: $data['Taxonomy_URL_5'], + taxonomyURL6: $data['Taxonomy_URL_6'], isHomePage: $data['homepageTest'], toggleURL: $toggleURL, hasBenefitCategory: $data['hasBenefitCategory'] ? '1' : '', benefitCategories: $data['benefitCategories'] ?: '', ); } + } diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/EventSubscriber/PublishedPagesSubscriber.php b/web/modules/custom/usagov_ssg_postprocessing/src/EventSubscriber/PublishedPagesSubscriber.php deleted file mode 100644 index f476e666c8..0000000000 --- a/web/modules/custom/usagov_ssg_postprocessing/src/EventSubscriber/PublishedPagesSubscriber.php +++ /dev/null @@ -1,259 +0,0 @@ -getHtml(); - - // LIBXML_SCHEMA_CREATE fixes a problem wherein DOMDocument would remove closing HTML - // tags within quoted text in a script element. See https://bugs.php.net/bug.php?id=74628 - $document = new \DOMDocument(); - @$document->loadHTML($html, LIBXML_SCHEMA_CREATE); - $xpath = new \DOMXPath($document); - - $csv_path = "modules/custom/usagov_ssg_postprocessing/files/published-pages.csv"; - $csv = []; - $fp = fopen($csv_path, 'c+'); - if ($fp != FALSE) { - flock($fp, LOCK_EX); - while (($line = fgetcsv($fp)) != FALSE) { - $csv[] = $line; - } - } - - // Set the pointer to the end of the array by default. - end($csv); - $pointer = (key($csv) == FALSE) ? 0 : key($csv) + 1; - - /** @var \DOMElement $node */ - foreach ($xpath->query('/html/head/script[contains(@id, "taxonomy-data")]') as $node) { - $script = $node->nodeValue; - $script = trim($script); - $script = ltrim($script, "dataLayer = "); - $script = rtrim($script, ";"); - $script = rtrim($script, ","); - // The following line prevents json_decode() from failing when there is an extra comma after the final element in an array. - $script = str_replace(",\n }", "\n }", $script); - $decoded = json_decode($script, TRUE); - $decoded = $decoded[0]; - if (empty($decoded)) { - print "WARNING: PublishedPagesSubscriber.php is skiping a page due to a bad dataLayer\n"; - continue; - } - - $url_replace = [ - "Taxonomy_URL_1", - "Taxonomy_URL_2", - "Taxonomy_URL_3", - "Taxonomy_URL_4", - "Taxonomy_URL_5", - "Taxonomy_URL_6" - ]; - - $header_replace = [ - "nodeID" => "Page ID", - "taxonomyID" => "Page ID", - "language" => "Taxonomy Level 1", - "Taxonomy_Text_2" => "Taxonomy Level 2", - "Taxonomy_Text_3" => "Taxonomy Level 3", - "Taxonomy_Text_4" => "Taxonomy Level 4", - "Taxonomy_Text_5" => "Taxonomy Level 5", - "Taxonomy_Text_6" => "Taxonomy Level 6", - "Taxonomy_URL_1" => "Taxonomy URL Level 1", - "Taxonomy_URL_2" => "Taxonomy URL Level 2", - "Taxonomy_URL_3" => "Taxonomy URL Level 3", - "Taxonomy_URL_4" => "Taxonomy URL Level 4", - "Taxonomy_URL_5" => "Taxonomy URL Level 5", - "Taxonomy_URL_6" => "Taxonomy URL Level 6", - "Page_Type" => "Page Type", - "basicPagesubType" => "Page Sub Type", - "contentType" => "Content Type", - - "homepageTest" => "Homepage?", - ]; - - $content_replace = [ - "en" => "USAGov English", - "es" => "USAGov Español", - ]; - - $order_map = [ - "Hierarchy Level", - "Page Type", - "Page Sub Type", - "Content Type", - "Friendly URL", - "Page ID", - "Page Title", - "Full URL", - "Taxonomy Level 1", - "Taxonomy Level 2", - "Taxonomy Level 3", - "Taxonomy Level 4", - "Taxonomy Level 5", - "Taxonomy Level 6", - "Taxonomy URL Level 1", - "Taxonomy URL Level 2", - "Taxonomy URL Level 3", - "Taxonomy URL Level 4", - "Taxonomy URL Level 5", - "Taxonomy URL Level 6", - "Homepage?", - "Toggle URL", - ]; - - // If the nodeID matches a line in the csv array, set the pointer to that element. - // TODO: this might be fragile. - if (!empty($csv)) { - $nodeIDElement = array_search("Page ID", $csv[0]); - $languageElement = array_search("Taxonomy Level 1", $csv[0]); - foreach ($csv as $key => $line) { - - if (!empty($line[$nodeIDElement]) && !empty($decoded["nodeID"]) && $line[$nodeIDElement] == $decoded["nodeID"]) { - if ($line[$languageElement] == $content_replace[$decoded["language"]]) { - $pointer = $key; - } - } - - if (!empty($line[$nodeIDElement]) && !empty($decoded["taxonomyID"]) && $line[$nodeIDElement] == 't_' . $decoded["taxonomyID"]) { - if ($line[$languageElement] == $content_replace[$decoded["language"]]) { - $pointer = $key; - } - } - } - } - - $host = \Drupal::request()->getSchemeAndHttpHost(); - - $title = $xpath->query('/html/head/title')->item(0)->nodeValue; - $title = (!empty($title)) ? str_replace(" | USAGov", "", $title) : "Not Found"; - - $decoded["Page Title"] = $title; - - $toggle_url = $xpath->query('/html/head/link[contains(@data-type, "altlang")]/@href')->item(0)->nodeValue; - $decoded["Toggle URL"] = ($toggle_url) ? $toggle_url : "None"; - - $hierarchy = 0; - $prev = ""; - foreach ($decoded as $key => $term) { - if (in_array($key, $url_replace)) { - if ($term != $prev) { - $hierarchy++; - $prev = $term; - } - } - } - $decoded["Hierarchy Level"] = $hierarchy; - - $url = ""; - foreach ($decoded as $name => $term) { - if ($name == "Taxonomy_Text_1") { - unset($decoded[$name]); - } - if ($name == "Taxonomy_URL_6") { - $url = $term; - } - if ($name == "language") { - $term = $content_replace[$term]; - } - foreach ($header_replace as $key => $item) { - if ($name == $key) { - if ($name == 'taxonomyID') { - $decoded[$item] = 't_' . $term; - } - else { - $decoded[$item] = $term; - } - unset($decoded[$name]); - } - } - } - // Tome can end up requesting existing URLs with the raw `/node/NID` path - // if a redirect to a node is set to the wrong language. It then proceeds - // which retrieves the wrong taxonomy info, which we should discard. - if (str_starts_with($url, '/node/') || str_starts_with($url, '/es/node/')) { - if ($fp != FALSE) { - fclose($fp); - } - return; - } - - // If this page is more than 5 levels deep in the taxonomy hierarchy, - // Then we may not be able to reconstruct its URL from the taxonomy URL. - // We can get reliably get it from the node. We could do this for all - // nodes, but that could negatively impact export performance. - if ($decoded['Page ID'] && $hierarchy > 5) { - $nid = $decoded['Page ID']; - if (!empty($nid)) { - if (substr($nid, 0, 2) === 't_') { - $tid = intval(substr($nid, 2)); - $termEntity = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($tid); - if (!empty($termEntity)) { - $url = $termEntity->toUrl()->toString(); - } - } - else { - $nodeEntity = \Drupal::entityTypeManager()->getStorage('node')->load($nid); - if (!empty($nodeEntity)) { - $url = $nodeEntity->toUrl()->toString(); - } - } - } - } - - $decoded["Friendly URL"] = (empty($url)) ? "/" : $url; - $decoded["Full URL"] = (empty($url)) ? $host . "/" : $host . $url; - - $orderedArray = array_merge(array_flip($order_map), $decoded); - - if (empty($csv)) { - foreach ($orderedArray as $name => $term) { - $csvheader[] = $name; - } - $csv[$pointer] = $csvheader; - $pointer++; - } - - foreach ($orderedArray as $name => $term) { - $csvline[] = $term; - } - - $csv[$pointer] = $csvline; - - if ($fp != FALSE) { - ftruncate($fp, 0); - rewind($fp); - foreach ($csv as $fields) { - fputcsv($fp, $fields); - } - fclose($fp); - } - } - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents() { -// $events[TomeStaticEvents::MODIFY_HTML][] = ['modifyHtml']; -// return $events; - } - -} diff --git a/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml b/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml index 942fa6b9e5..03368d006e 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml +++ b/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml @@ -35,12 +35,11 @@ usagov_ssg_postprocessing.site_lag_test: _permission: 'access administration pages' usagov_ssg_postprocessing.published_pages_csv: - path: '/published-pages.csv' + path: '/modules/custom/usagov_ssg_postprocessing/files/published-pages.csv' defaults: - _controller: '\Drupal\usagov_ssg_postprocessing\Controller\PublishedPagesController::buildCSV' + _controller: '\Drupal\usagov_ssg_postprocessing\Controller\PublishedPagesController::buildFile' _title: 'Generate published pages CSV' options: no_cache: 'TRUE' requirements: - _access: 'TRUE' - + _permission: 'access administration pages' diff --git a/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.services.yml b/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.services.yml index 564929322a..42ab4a2e4e 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.services.yml +++ b/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.services.yml @@ -8,10 +8,6 @@ services: class: '\Drupal\usagov_ssg_postprocessing\EventSubscriber\PagerPathSubscriber' tags: - { name: 'event_subscriber' } - usagov_ssg_postprocessing_published_pages_events_subscriber: - class: '\Drupal\usagov_ssg_postprocessing\EventSubscriber\PublishedPagesSubscriber' - tags: - - { name: 'event_subscriber' } usagov_ssg_postprocessing_request_prepare_events_subscriber: class: '\Drupal\usagov_ssg_postprocessing\EventSubscriber\RequestPrepareSubscriber' arguments: ['@path_alias.manager', '@entity_type.manager', '@current_route_match'] diff --git a/web/modules/custom/usagov_wizard/src/EventSubscriber/DatalayerAlterSubscriber.php b/web/modules/custom/usagov_wizard/src/EventSubscriber/DatalayerAlterSubscriber.php index ae2e0db239..12485e9e8b 100644 --- a/web/modules/custom/usagov_wizard/src/EventSubscriber/DatalayerAlterSubscriber.php +++ b/web/modules/custom/usagov_wizard/src/EventSubscriber/DatalayerAlterSubscriber.php @@ -5,8 +5,6 @@ use Drupal\Core\Breadcrumb\BreadcrumbManager; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Routing\CurrentRouteMatch; -use Drupal\Core\Url; -use Drupal\taxonomy\Entity\Term; use Drupal\usa_twig_vars\Event\DatalayerAlterEvent; use Drupal\usagov_wizard\MenuChecker; use Drupal\usagov_wizard\WizardDataLayer; @@ -45,4 +43,5 @@ public function onDatalayerAlter(DatalayerAlterEvent $event): void { $builder = new WizardDataLayer($term, $this->entityTypeManager); $event->datalayer = $builder->getData($event->datalayer); } + } diff --git a/web/modules/custom/usagov_wizard/src/WizardDataLayer.php b/web/modules/custom/usagov_wizard/src/WizardDataLayer.php index acc8180d4a..a3cb507815 100644 --- a/web/modules/custom/usagov_wizard/src/WizardDataLayer.php +++ b/web/modules/custom/usagov_wizard/src/WizardDataLayer.php @@ -109,4 +109,5 @@ public function getData(array $data = []): array { ksort($urls); return array_merge($data, $urls); } + } From 110add2a98b233b690c26541f1b34b9e9680c601 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Wed, 4 Dec 2024 22:13:00 -0500 Subject: [PATCH 11/29] USAGOV-2073-published-pages: Adds a drush command to generate published pages CSV. --- .../Controller/PublishedPagesController.php | 1 + .../src/Data/PublishedPagesRow.php | 6 +- .../Drush/Commands/PublishedPagesCommands.php | 237 ++++++++++++++++++ 3 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 web/modules/custom/usagov_ssg_postprocessing/src/Drush/Commands/PublishedPagesCommands.php diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php index 32ce3be39e..0d2638a364 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php @@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; class PublishedPagesController extends ControllerBase { diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index 4aff1e36ad..6e2aceaac7 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -115,7 +115,7 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL } $toggleURL = NULL; - if ($node->field_language_toggle[0]->target_id) { + if (isset($node->field_language_toggle[0]) && $node->field_language_toggle[0]?->target_id) { if ($data['homepageTest'] === 'homepage' && $data['language'] === 'en') { $toggleURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_ES; } @@ -159,7 +159,7 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL isHomePage: $data['homepageTest'], toggleURL: $toggleURL ?? 'None', hasBenefitCategory: $data['hasBenefitCategory'] ? '1' : '', - benefitCategories: $data['benefitCategories'] ?: '', + benefitCategories: $data['benefitCategories'] ?? '', ); } @@ -209,7 +209,7 @@ public static function datalayerForWizard(array $data, Term $term, string $baseU isHomePage: $data['homepageTest'], toggleURL: $toggleURL, hasBenefitCategory: $data['hasBenefitCategory'] ? '1' : '', - benefitCategories: $data['benefitCategories'] ?: '', + benefitCategories: $data['benefitCategories'] ?? '', ); } diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Drush/Commands/PublishedPagesCommands.php b/web/modules/custom/usagov_ssg_postprocessing/src/Drush/Commands/PublishedPagesCommands.php new file mode 100644 index 0000000000..2417812986 --- /dev/null +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Drush/Commands/PublishedPagesCommands.php @@ -0,0 +1,237 @@ +get('entity_type.manager'), + configFactory: $container->get('config.factory'), + dispatcher: $container->get('event_dispatcher'), + request: $container->get('request_stack')->getCurrentRequest(), + router: $container->get('router.no_access_checks'), + pathAliasManager: $container->get('path_alias.manager'), + breadcrumb: $container->get('breadcrumb'), + languageManager: $container->get('language_manager') + ); + } + + /** + * Export published pages CSV + */ + #[CLI\Command(name: 'usagov:published-csv', aliases: ['usapubcsv'])] + #[CLI\Argument(name: 'outfile', description: 'Path for output file')] + #[CLI\Usage( + name: 'usagov_ssg_postprocessing:published-csv', + description: 'Usage description') + ] + public function publishedCsv($outfile) { + $this->logger()->info('Publishing CSV to ' . $outfile); + +// if (!is_writable($outfile)) { +// $this->output()->writeln("Can not write to destination file."); +// exit(1); +// } + + $out = fopen($outfile, 'w'); + fputcsv($out, $this->csvHeader); + // Render published pages to output file + $this->saveNodeRows($out); + $this->saveWizardRows($out); + fclose($out); + + $this->logger()->success(dt('Done.')); + } + + protected function saveNodeRows($out): void { + $nids = $this->entityTypeManager + ->getStorage('node') + ->getQuery() + ->condition('type', [ + 'basic_page', + 'bears_life_event', + 'directory_record', + 'federal_directory_index', + 'state_directory_record', + 'wizard_step', + ], 'IN') + ->condition('status', 1) //published + ->sort('nid', 'ASC') + ->accessCheck(TRUE) + ->sort('nid') + ->execute(); + + foreach ($nids as $nid) { + $node = $this->entityTypeManager->getStorage('node')->load($nid); + $row = $this->getNodeRow($node)->toArray(); + + $row = array_map(fn($col) => trim($col), $row); + fputcsv($out, $row); + + $origLanguage = $node->language(); + if ($languages = $node->getTranslationLanguages()) { + foreach ($languages as $lang) { + if ($lang->getId() !== $origLanguage->getId()) { + // export translated node + $trNode = $node->getTranslation($lang->getId()); + $trRow = $this->getNodeRow($trNode); + $fields = array_map(fn($field) => trim($field), $trRow->toArray()); + fputcsv($out, $fields); + } + } + } + } + } + + protected function saveWizardRows($out): void { + $tids = $this->entityTypeManager + ->getStorage('taxonomy_term') + ->getQuery() + ->condition('vid', 'wizard') + ->condition('status', 1) //published + ->sort('tid', 'ASC') + ->accessCheck(TRUE) + ->sort('tid') + ->execute(); + + foreach ($tids as $tid) { + $wizard = $this->entityTypeManager->getStorage('taxonomy_term')->load($tid); + $row = $this->getWizardRow($wizard); + fputcsv($out, $row->toArray()); + } + } + + protected function getNodeRow(Node $node): PublishedPagesRow { + $front_uri = $this->configFactory->get('system.site')->get('page.front'); + $alias = $this->pathAliasManager->getAliasByPath('/node/' . $node->id()); + + $isFront = ($alias === $front_uri); + + $pageType = usa_twig_vars_get_page_type($node); + + // The following is "dragons abound here" but Drupal does not make it possible + // to change the language for building breadcrumbs after a request has started. + $negotiatedProp = new \ReflectionProperty(get_class($this->languageManager), 'negotiatedLanguages'); + $value = $negotiatedProp->getValue($this->languageManager); + $value['language_content'] = $node->language(); + $negotiatedProp->setValue($this->languageManager, $value); + + // To get the right breadcrumb/active trail for this routeMatch, the menu_breadcrumb module + // must be configured to "Derive MenuActiveTrail from RouteMatch" + $datalayer = new TaxonomyDatalayerBuilder( + routeMatch: $this->getRouteMatchForNode($node), + breadcrumbManager: $this->breadcrumb, + node: $node, + isFront: $isFront, + basicPagesubType: $pageType ?? NULL, + ); + $data = $datalayer->build(); + + $data = $this->alterDatalayer($data); + + $baseURL = $this->request->getSchemeAndHttpHost(); + return PublishedPagesRow::datalayerForNode($data, $node, $baseURL); + } + + /** + * Get a valid routeMatch object for a node + * + * To get the same datalayer output, we need to set up a routeMatch for each + * entity we are exporting that the datalayer module can look up via the + * breadcrumb manager. + */ + private function getRouteMatchForNode(Node $node): RouteMatchInterface { + $route = $this->router->match('/node/' . $node->id()); + + return new RouteMatch( + route_name: $route['_route'], + route: $route['_route_object'], + parameters: ['node' => $node], + raw_parameters: ['node' => $node->id(), 'language' => $node->language()->getId()] + ); + } + + protected function getWizardRow(Term $wizard): PublishedPagesRow { + $builder = new WizardDataLayer($wizard, $this->entityTypeManager); + $data = $builder->getData([]); + + $baseURL = $this->request->getSchemeAndHttpHost(); + return PublishedPagesRow::datalayerForWizard($data, $wizard, $baseURL); + } + + private function alterDatalayer(array $data): array { + // Let other modules add to the datalayer payload. + $datalayerEvent = new DatalayerAlterEvent($data); + $this->dispatcher->dispatch($datalayerEvent, DatalayerAlterEvent::EVENT_NAME); + return $datalayerEvent->datalayer; + } + +} From f8faf475337a9dadb131cc190816bf178dc0da78 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Wed, 4 Dec 2024 23:34:56 -0500 Subject: [PATCH 12/29] USAGOV-2073-published-pages: Generate the published pages CSV after tome export completes. --- scripts/tome-static.sh | 4 + .../custom/usa_twig_vars/usa_twig_vars.module | 1 - .../Controller/PublishedPagesController.php | 216 ------------------ .../Drush/Commands/PublishedPagesCommands.php | 25 +- .../usagov_ssg_postprocessing.routing.yml | 10 - 5 files changed, 17 insertions(+), 239 deletions(-) delete mode 100644 web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php diff --git a/scripts/tome-static.sh b/scripts/tome-static.sh index a0c202c578..050532090b 100755 --- a/scripts/tome-static.sh +++ b/scripts/tome-static.sh @@ -32,5 +32,9 @@ mkdir -p /var/www/html # time drush tome:static -y --uri=$URI --process-count=5 --path-count=1 time drush tome:static -y --uri=$URI --process-count=$TOME_PROCESS_COUNT --path-count=10 TOME_SUCCESS=$? + echo "Finished Static Site Generation : "$(date) +# path is relative to drupal's web dir +time drush usapubcsv modules/custom/usagov_ssg_postprocessing/files/published-pages.csv +echo "Exported published-pages.csv" exit $TOME_SUCCESS diff --git a/web/modules/custom/usa_twig_vars/usa_twig_vars.module b/web/modules/custom/usa_twig_vars/usa_twig_vars.module index 35c7fbbb78..e6f71cb75b 100644 --- a/web/modules/custom/usa_twig_vars/usa_twig_vars.module +++ b/web/modules/custom/usa_twig_vars/usa_twig_vars.module @@ -7,7 +7,6 @@ use Drupal\Core\Render\Markup; use Drupal\Core\Url; -use Drupal\block\Entity\Block; use Drupal\node\Entity\Node; use Drupal\node\NodeInterface; use Drupal\path_alias\PathAliasInterface; diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php b/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php deleted file mode 100644 index 0d2638a364..0000000000 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Controller/PublishedPagesController.php +++ /dev/null @@ -1,216 +0,0 @@ -get('event_dispatcher'), - request: $container->get('request_stack')->getCurrentRequest(), - router: $container->get('router.no_access_checks'), - pathAliasManager: $container->get('path_alias.manager'), - breadcrumb: $container->get('breadcrumb'), - ); - } - - public function buildFile() { - // Set up to echo CSV rows to STDOUT/browser. - ob_start(); - $out = fopen('php://output', 'w'); - fputcsv($out, $this->csvHeader); - // Render published pages to output stream - $this->saveNodeRows($out); - $this->saveWizardRows($out); - // Write contents to output stream - $content = ob_get_clean(); - fclose($out); - // Output CSV response - $response = new Response(); - $response->headers->set('Content-Type', 'text/plain'); - $response->setContent($content); - return $response->send(); - } - - protected function saveNodeRows($out): void { - $nids = $this->entityTypeManager() - ->getStorage('node') - ->getQuery() - ->condition('type', [ - 'basic_page', - 'bears_life_event', - 'directory_record', - 'federal_directory_index', - 'state_directory_record', - 'wizard_step', - ], 'IN') - ->condition('status', 1) //published - ->sort('nid', 'ASC') - ->accessCheck(TRUE) - ->sort('nid') - ->execute(); - - foreach ($nids as $nid) { - $node = $this->entityTypeManager()->getStorage('node')->load($nid); - $row = $this->getNodeRow($node)->toArray(); - - $row = array_map(fn($col) => trim($col), $row); - fputcsv($out, $row); - - $origLanguage = $node->language(); - if ($languages = $node->getTranslationLanguages()) { - foreach ($languages as $lang) { - if ($lang->getId() !== $origLanguage->getId()) { - // export translated node - $trNode = $node->getTranslation($lang->getId()); - $trRow = $this->getNodeRow($trNode); - $fields = array_map(fn($field) => trim($field), $trRow->toArray()); - fputcsv($out, $fields); - } - } - } - } - } - - protected function saveWizardRows($out): void { - $tids = $this->entityTypeManager() - ->getStorage('taxonomy_term') - ->getQuery() - ->condition('vid', 'wizard') - ->condition('status', 1) //published - ->sort('tid', 'ASC') - ->accessCheck(TRUE) - ->sort('tid') - ->execute(); - - foreach ($tids as $tid) { - $wizard = $this->entityTypeManager()->getStorage('taxonomy_term')->load($tid); - $row = $this->getWizardRow($wizard); - fputcsv($out, $row->toArray()); - } - } - - protected function getNodeRow(Node $node): PublishedPagesRow { - $front_uri = $this->config('system.site')->get('page.front'); - $alias = $this->pathAliasManager->getAliasByPath('/node/' . $node->id()); - - $isFront = ($alias === $front_uri); - - $pageType = usa_twig_vars_get_page_type($node); - - $languageManager = $this->languageManager(); - // The following is "dragons abound here" but Drupal does not make it possible - // to change the language for building breadcrumbs after a request has started. - $negotiatedProp = new \ReflectionProperty(get_class($languageManager), 'negotiatedLanguages'); - $value = $negotiatedProp->getValue($languageManager); - $value['language_content'] = $node->language(); - $negotiatedProp->setValue($this->languageManager, $value); - - // To get the right breadcrumb/active trail for this routeMatch, the menu_breadcrumb module - // must be configured to "Derive MenuActiveTrail from RouteMatch" - $datalayer = new TaxonomyDatalayerBuilder( - routeMatch: $this->getRouteMatchForNode($node), - breadcrumbManager: $this->breadcrumb, - node: $node, - isFront: $isFront, - basicPagesubType: $pageType ?? NULL, - ); - $data = $datalayer->build(); - - $data = $this->alterDatalayer($data); - - $baseURL = $this->request->getSchemeAndHttpHost(); - return PublishedPagesRow::datalayerForNode($data, $node, $baseURL); - } - - /** - * Get a valid routeMatch object for a node - * - * To get the same datalayer output, we need to set up a routeMatch for each - * entity we are exporting that the datalayer module can look up via the - * breadcrumb manager. - */ - private function getRouteMatchForNode(Node $node): RouteMatchInterface { - $route = $this->router->match('/node/' . $node->id()); - - return new RouteMatch( - route_name: $route['_route'], - route: $route['_route_object'], - parameters: ['node' => $node], - raw_parameters: ['node' => $node->id(), 'language' => $node->language()->getId()] - ); - } - - protected function getWizardRow(Term $wizard): PublishedPagesRow { - $builder = new WizardDataLayer($wizard, $this->entityTypeManager); - $data = $builder->getData([]); - - $baseURL = $this->request->getSchemeAndHttpHost(); - return PublishedPagesRow::datalayerForWizard($data, $wizard, $baseURL); - } - - private function alterDatalayer(array $data): array { - // Let other modules add to the datalayer payload. - $datalayerEvent = new DatalayerAlterEvent($data); - $this->dispatcher->dispatch($datalayerEvent, DatalayerAlterEvent::EVENT_NAME); - return $datalayerEvent->datalayer; - } - -} diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Drush/Commands/PublishedPagesCommands.php b/web/modules/custom/usagov_ssg_postprocessing/src/Drush/Commands/PublishedPagesCommands.php index 2417812986..66cad179f8 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Drush/Commands/PublishedPagesCommands.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Drush/Commands/PublishedPagesCommands.php @@ -6,9 +6,6 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Language\LanguageManagerInterface; -use Drush\Attributes as CLI; -use Drush\Commands\DrushCommands; -use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Routing\RouteMatch; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\Router; @@ -19,9 +16,11 @@ use Drupal\usa_twig_vars\TaxonomyDatalayerBuilder; use Drupal\usagov_ssg_postprocessing\Data\PublishedPagesRow; use Drupal\usagov_wizard\WizardDataLayer; +use Drush\Attributes as CLI; +use Drush\Commands\DrushCommands; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; /** * A Drush commandfile. @@ -94,21 +93,23 @@ public static function create(ContainerInterface $container) { description: 'Usage description') ] public function publishedCsv($outfile) { - $this->logger()->info('Publishing CSV to ' . $outfile); - -// if (!is_writable($outfile)) { -// $this->output()->writeln("Can not write to destination file."); -// exit(1); -// } + $this->output()->writeln('Publishing CSV to ' . $outfile . ''); $out = fopen($outfile, 'w'); + + if (!str_starts_with($outfile, '/')) { + $this->logger()->warning('Relative path given, current working dir: {dir}', ['dir' => getcwd()]); + + } + if (FALSE === $out) { + $this->output()->writeln("Can not write to destination file."); + exit(1); + } fputcsv($out, $this->csvHeader); // Render published pages to output file $this->saveNodeRows($out); $this->saveWizardRows($out); fclose($out); - - $this->logger()->success(dt('Done.')); } protected function saveNodeRows($out): void { diff --git a/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml b/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml index 03368d006e..bbaeaa631f 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml +++ b/web/modules/custom/usagov_ssg_postprocessing/usagov_ssg_postprocessing.routing.yml @@ -33,13 +33,3 @@ usagov_ssg_postprocessing.site_lag_test: no_cache: 'TRUE' requirements: _permission: 'access administration pages' - -usagov_ssg_postprocessing.published_pages_csv: - path: '/modules/custom/usagov_ssg_postprocessing/files/published-pages.csv' - defaults: - _controller: '\Drupal\usagov_ssg_postprocessing\Controller\PublishedPagesController::buildFile' - _title: 'Generate published pages CSV' - options: - no_cache: 'TRUE' - requirements: - _permission: 'access administration pages' From e352c1d4cb93fa32cd4c7b258905d6224254de9a Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Wed, 4 Dec 2024 23:41:56 -0500 Subject: [PATCH 13/29] USAGOV-2073-published-pages: Update menu breadcrubm config to work on RouteMatch --- config/sync/menu_breadcrumb.settings.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/config/sync/menu_breadcrumb.settings.yml b/config/sync/menu_breadcrumb.settings.yml index f9b4752401..71042fa0a8 100644 --- a/config/sync/menu_breadcrumb.settings.yml +++ b/config/sync/menu_breadcrumb.settings.yml @@ -12,13 +12,18 @@ add_home: true front_title: 0 exclude_empty_url: false exclude_disabled_menu_items: false -derived_active_trail: false +derived_active_trail: true menu_breadcrumb_menus: main: enabled: 0 weight: -10 taxattach: 0 langhandle: 0 + account: + enabled: 0 + weight: 0 + taxattach: 0 + langhandle: 0 admin: enabled: 0 weight: 0 @@ -44,12 +49,27 @@ menu_breadcrumb_menus: weight: 0 taxattach: 0 langhandle: 1 + primary-footer: + enabled: 0 + weight: 0 + taxattach: 0 + langhandle: 0 + primary-footer-spanish: + enabled: 0 + weight: 0 + taxattach: 0 + langhandle: 0 tools: enabled: 0 weight: 0 taxattach: 0 langhandle: 0 - account: + top-navigation: + enabled: 0 + weight: 0 + taxattach: 0 + langhandle: 0 + top-navigation-es: enabled: 0 weight: 0 taxattach: 0 From ae8806f71a501164761c862bf30ac2d10cfd773f Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Thu, 5 Dec 2024 11:31:08 -0500 Subject: [PATCH 14/29] USAGOV-2117-phpcs-local: Fix word wrapping to meet column length --- web/themes/custom/usagov/usagov.theme | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/themes/custom/usagov/usagov.theme b/web/themes/custom/usagov/usagov.theme index 4a2e2d4693..6604a05247 100644 --- a/web/themes/custom/usagov/usagov.theme +++ b/web/themes/custom/usagov/usagov.theme @@ -27,8 +27,9 @@ function usagov_preprocess_html(&$variables) { function generate_faq(&$node) { $faq = []; - // While a node may have its FAQ-Page checked, this does not guarantee the body field is not empty. - // When it is empty, there is nothing we can do here. We will bail to prevent errors (see USAGOV-1925). + // While a node may have its FAQ-Page checked, this does not guarantee the + // body field is not empty. When it is empty, there is nothing we can do here. + // We will bail to prevent errors (see USAGOV-1925). if (empty($node->get('body')) || empty($node->get('body')[0]) || empty($node->get('body')[0]->value)) { return; } From 70a6594a7fb353e0d4abb3d5d2dd5ad4bc387a39 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Thu, 5 Dec 2024 11:54:15 -0500 Subject: [PATCH 15/29] USAGOV-2117-phpcs-local: Add dependencies for checking code style and php linting Add composer scripts and helper for running the sniffer --- bin/changed-files | 9 + composer.json | 24 +++ composer.lock | 445 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 476 insertions(+), 2 deletions(-) create mode 100755 bin/changed-files diff --git a/bin/changed-files b/bin/changed-files new file mode 100755 index 0000000000..5c39395093 --- /dev/null +++ b/bin/changed-files @@ -0,0 +1,9 @@ +#!/bin/bash + +CURRENT_BRANCH=`git branch --show-current` +# Get the changes between current branch and dev +CHANGED=`git diff --name-only --diff-filter=ARM dev $CURRENT_BRANCH` + +if [ "$CURRENT_BRANCH" != "dev" ]; then + echo $CHANGED; +fi diff --git a/composer.json b/composer.json index ecf8b66456..5fb6d84210 100644 --- a/composer.json +++ b/composer.json @@ -162,5 +162,29 @@ "drupal/ckeditor_templates" ] } + }, + "require-dev": { + "drupal/coder": "^8.3", + "php-parallel-lint/php-parallel-lint": "^1.4" + }, + "scripts": { + "changed-files": [ + "bin/changed-files" + ], + "phpcs-errors": [ + "vendor/bin/phpcs -n --standard=.phpcs.xml.dist" + ], + "phpcs-strict": [ + "vendor/bin/phpcs --standard=.phpcs.xml.dist" + ], + "phpcs-changes": [ + "vendor/bin/phpcs -n --standard=.phpcs.xml.dist `bin/changed-files`" + ], + "phpcs-changes-strict": [ + "vendor/bin/phpcs --standard=.phpcs.xml.dist `bin/changed-files`" + ], + "php-lint": [ + "vendor/bin/parallel-lint -e php,module,inc,install,test,profile,theme ./web/modules/custom ./web/themes/custom" + ] } } diff --git a/composer.lock b/composer.lock index 740db231cb..2231113114 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "06ca7c5968b37fb09f0f66a126ffa880", + "content-hash": "9ccd7f5b73007114f90aeb0ed47c9e75", "packages": [ { "name": "asm89/stack-cors", @@ -11627,7 +11627,448 @@ "time": "2023-04-15T19:07:00+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" + }, + { + "name": "drupal/coder", + "version": "8.3.26", + "source": { + "type": "git", + "url": "https://github.com/pfrenssen/coder.git", + "reference": "fd98546ce3373aa7767240901eda47963ce64c82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pfrenssen/coder/zipball/fd98546ce3373aa7767240901eda47963ce64c82", + "reference": "fd98546ce3373aa7767240901eda47963ce64c82", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1 || ^1.0.0", + "ext-mbstring": "*", + "php": ">=7.2", + "sirbrillig/phpcs-variable-analysis": "^2.11.7", + "slevomat/coding-standard": "^8.11", + "squizlabs/php_codesniffer": "^3.9.1", + "symfony/yaml": ">=3.4.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.7.12", + "phpunit/phpunit": "^8.0" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "Drupal\\": "coder_sniffer/Drupal/", + "DrupalPractice\\": "coder_sniffer/DrupalPractice/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "Coder is a library to review Drupal code.", + "homepage": "https://www.drupal.org/project/coder", + "keywords": [ + "code review", + "phpcs", + "standards" + ], + "support": { + "issues": "https://www.drupal.org/project/issues/coder", + "source": "https://www.drupal.org/project/coder" + }, + "time": "2024-11-28T23:14:29+00:00" + }, + { + "name": "php-parallel-lint/php-parallel-lint", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", + "reference": "6db563514f27e19595a19f45a4bf757b6401194e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6db563514f27e19595a19f45a4bf757b6401194e", + "reference": "6db563514f27e19595a19f45a4bf757b6401194e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.3.0" + }, + "replace": { + "grogy/php-parallel-lint": "*", + "jakub-onderka/php-parallel-lint": "*" + }, + "require-dev": { + "nette/tester": "^1.3 || ^2.0", + "php-parallel-lint/php-console-highlighter": "0.* || ^1.0", + "squizlabs/php_codesniffer": "^3.6" + }, + "suggest": { + "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet" + }, + "bin": [ + "parallel-lint" + ], + "type": "library", + "autoload": { + "classmap": [ + "./src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "ahoj@jakubonderka.cz" + } + ], + "description": "This tool checks the syntax of PHP files about 20x faster than serial check.", + "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", + "keywords": [ + "lint", + "static analysis" + ], + "support": { + "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", + "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.4.0" + }, + "time": "2024-03-27T12:14:49+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.33.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" + }, + "time": "2024-10-13T11:25:22+00:00" + }, + { + "name": "sirbrillig/phpcs-variable-analysis", + "version": "v2.11.21", + "source": { + "type": "git", + "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", + "reference": "eb2b351927098c24860daa7484e290d3eed693be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/eb2b351927098c24860daa7484e290d3eed693be", + "reference": "eb2b351927098c24860daa7484e290d3eed693be", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "squizlabs/php_codesniffer": "^3.5.6" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", + "phpcsstandards/phpcsdevcs": "^1.1", + "phpstan/phpstan": "^1.7", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0 || ^10.5.32 || ^11.3.3", + "sirbrillig/phpcs-import-detection": "^1.1", + "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "VariableAnalysis\\": "VariableAnalysis/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Sam Graham", + "email": "php-codesniffer-variableanalysis@illusori.co.uk" + }, + { + "name": "Payton Swick", + "email": "payton@foolord.com" + } + ], + "description": "A PHPCS sniff to detect problems with variables.", + "keywords": [ + "phpcs", + "static analysis" + ], + "support": { + "issues": "https://github.com/sirbrillig/phpcs-variable-analysis/issues", + "source": "https://github.com/sirbrillig/phpcs-variable-analysis", + "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" + }, + "time": "2024-12-02T16:37:49+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.15.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "7d1d957421618a3803b593ec31ace470177d7817" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", + "reference": "7d1d957421618a3803b593ec31ace470177d7817", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.60", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.16", + "phpstan/phpstan-strict-rules": "1.5.2", + "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2024-03-09T15:20:58+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.11.1", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", + "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-11-16T12:02:36+00:00" + } + ], "aliases": [], "minimum-stability": "dev", "stability-flags": { From 7c0028ae82776ec8ef05550d304117c69d242f87 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Thu, 5 Dec 2024 12:03:19 -0500 Subject: [PATCH 16/29] USAGOV-2117-phpcs-local: Document usage of composer scripts for linters. --- README.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 11890913c2..46ff6b8152 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ To access the Drupal Portal to make any additional configurations, you will need Log out as root, and log in with your own user account. -**Note:** You will need to repeat these steps any time you re-load the database from a backup. +**Note:** You will need to repeat these steps any time you re-load the database from a backup. ### Automated tests setup (cypress) @@ -183,12 +183,12 @@ We use [Cypress](cypress.io). Note that we use only the Cypress App, _not_ Cypre * Tests run in the `cypress` Docker container. * The tests themselves are in the `automated_tests/e2e-cypress` directory. -* Twig debugging will break some of the tests! Turn it off before running tests to get the most accurate results. +* Twig debugging will break some of the tests! Turn it off before running tests to get the most accurate results. ## Minimal setup for headless tests -1. Supply Drupal *credentials* for the automated tests: Edit the file `env.local.cypress`. Supply a valid Drupal user name and password for `cypressCmsUser` and `cypressCmsPass`. +1. Supply Drupal *credentials* for the automated tests: Edit the file `env.local.cypress`. Supply a valid Drupal user name and password for `cypressCmsUser` and `cypressCmsPass`. 2. Run `docker compose up` to (re-)create the cypress container with the new environment variables. @@ -196,7 +196,7 @@ We use [Cypress](cypress.io). Note that we use only the Cypress App, _not_ Cypre You can run `npx cypress run --spec cypress/e2e` to run the entire test suite, or specify a smaller subset like `cypress/e2e/functional`. - The **Report** will be written to automated_tests/e2e-cypress/cypress/reports/html/index.html and you can open it in your web browser by navigating to that file and opening it. Cypress will report that it wrote the tests to /app/e2e-cypress/cypress/reports/html/index.html, which is the location of that file in the volume mounted to the cypress docker container. + The **Report** will be written to automated_tests/e2e-cypress/cypress/reports/html/index.html and you can open it in your web browser by navigating to that file and opening it. Cypress will report that it wrote the tests to /app/e2e-cypress/cypress/reports/html/index.html, which is the location of that file in the volume mounted to the cypress docker container. Note: The first time you run bin/init, it will create the `env.local.cypress` file by copying `env.default.cypress`. The default `cypressBaseUrl` in that file should be correct for running tests against your local dev site. @@ -232,7 +232,7 @@ This assumes you're using homebrew. The "network client" you're enabling this for is the virtual machine running in your cypress container. -4. Reboot your computer. (You need to reboot once after installing XQuartz. Thereafter, when you change your XQuartz settings you need to restart XQuartz, but not reboot.) +4. Reboot your computer. (You need to reboot once after installing XQuartz. Thereafter, when you change your XQuartz settings you need to restart XQuartz, but not reboot.) Proceed to [Allow cypress to open an X window](#allow-cypress-to-open-an-x-window) @@ -320,6 +320,24 @@ If you make any changes to the `scss` or `js` files, make sure to check for lint [back to top](#usagov-2021) +## Checking PHP Code style and syntax errors + +PHPCodesniffer and the parallel linting tools should be installed automatically on a local environment via `composer install`. PHPCodeSniffer is used to ensure new code follows Drupal's coding standard. The parallel linter will check for PHP syntax errors. If they detect any errors, they must be fixed before a PR of changes can be accepted. + +The following composer scripts are aliases for running these tools. development setup + +* Check for code style errors across all project files. Must have zero errors: + `./bin/composer phpcs-errors`: +* Check for code style errors and warnings across all project files. + `./bin/composer phpcs-strict` +* Check for code style errors in current branch. Must have zero errors: + `./bin/composer phpcs-changes` +* Check for code style errors and warnings in current branch. + `./bin/composer phpcs-changes-strict` +* Check for PHP lint errors + `./bin/composer php-lint` + + ## Project Restart/Reset Sometimes, Docker problems arise after an upgrade and a more complete restart is needed. After closing down and destroying the existing containers, networks, and volumes the procedure is the same as the full project setup. From aa9e032f4e86485a3c6d8d408512916afb049d26 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Thu, 5 Dec 2024 12:06:06 -0500 Subject: [PATCH 17/29] USAGOV-2117-phpcs-local: Wrap lines that exceed 100 chars --- web/themes/custom/usagov/usagov.theme | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/themes/custom/usagov/usagov.theme b/web/themes/custom/usagov/usagov.theme index 6604a05247..8d7949e074 100644 --- a/web/themes/custom/usagov/usagov.theme +++ b/web/themes/custom/usagov/usagov.theme @@ -146,7 +146,8 @@ function generate_faq(&$node) { function faq_process_components(&$dom) { // Iterate through embedded paragraphs $embeddedParagraphElements = $dom->getElementsByTagName('drupal-paragraph'); - // Loop backwards to allow for removing elements along the way without losing track of our position + // Loop backwards to allow for removing elements along the way without losing + // track of our position for ($n = $embeddedParagraphElements->length - 1; $n >= 0; --$n) { $element = $embeddedParagraphElements->item($n); // Get the component @@ -156,8 +157,8 @@ function faq_process_components(&$dom) { // Process component by its type if ($component == NULL) { - // No entity exists for this paragraph component. It is probably a reference to a deleted component. - // Remove the element and move on. + // No entity exists for this paragraph component. It is probably a reference + // to a deleted component. Remove the element and move on. $element->parentNode->removeChild($element); break; } @@ -193,7 +194,6 @@ function faq_process_components(&$dom) { } elseif ($componentType == "uswds_alert" && $component?->get('field_alert_status')[0]?->value == NULL) { // $component is a grey alert - // Insert a

element with the alert's body content $alertBody = $component->get('field_alert_body')[0]->value; $alertElement = $dom->createElement('p'); @@ -266,7 +266,8 @@ function faq_answer_inner_html(&$answer) { } /** - * children_of_active_menu_item is a recursive helper function for finding the children of the active menu item + * children_of_active_menu_item is a recursive helper function for finding the + * children of the active menu item */ function children_of_active_menu_item(&$items) { $result = NULL; @@ -382,7 +383,6 @@ function usagov_preprocess_block(&$variables) { count($childNode->get('field_navigation_banner_image')) && $childNode->get('field_navigation_banner_image')[0]->entity ) { - $file_url_generator = \Drupal::service('file_url_generator'); // To allow for image_style (webp compression) to apply. $banner_uri = $childNode->get('field_navigation_banner_image')[0]->entity->get('field_media_image')->entity->getFileUri(); $data->navigation_banner_image = $banner_uri; From b01cf6999a852df995f104ff9ba44f4d61bc9116 Mon Sep 17 00:00:00 2001 From: arpage Date: Thu, 5 Dec 2024 20:31:35 -0500 Subject: [PATCH 18/29] USAGOV-1696-fix-git-annotation-parser: Fix error output when no arguments are provided. Also tested on Mac. --- bin/deploy/git-annotation-parser.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/bin/deploy/git-annotation-parser.sh b/bin/deploy/git-annotation-parser.sh index 3a34a1d07e..7d4a608263 100755 --- a/bin/deploy/git-annotation-parser.sh +++ b/bin/deploy/git-annotation-parser.sh @@ -21,16 +21,13 @@ else exit 1 fi -# just testing? -if [ x$1 == x"--dryrun" ]; then - export echo=echo - shift -fi - -SPACE=${1:-please-provide-space-as-first-argument} -SSPACE=$(echo "$SPACE" | tr '[:upper:]' '[:lower:]') ## lowercase, so tags are properly formatted -#assertCurSpace "$SPACE" ### <-- no need to assert that we're actually in $SPACE, because we're not doing anything w/ CF - just git +SPACE=$1 +if [ -z "$SPACE" ]; then + echo "First argument must be a valid CF space name" + exit 1 +fi; shift +SSPACE=$(echo "$SPACE" | tr '[:upper:]' '[:lower:]') ## lowercase, so tags are properly formatted # 1. Find the name of the latest annotated git tag matching our production post-deployment tag format # 2. Query the content field of the reference attached to the tag, and make sure it contains correctly formated build number and digest hashes From a7baf0f6950fa86e9a9bb9eefb9759dc2a6f7256 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Fri, 6 Dec 2024 16:39:05 -0500 Subject: [PATCH 19/29] USAGOV-2117-phpcs-local: Merging in Drupal 10.3 update, regen composer --- composer.lock | 451 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 446 insertions(+), 5 deletions(-) diff --git a/composer.lock b/composer.lock index 26b42f865d..e08d41dbba 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "93324a928ad5a44abbc3c4ab0c967cd6", + "content-hash": "750e25aca453a5fccca5ae752bbcd6e3", "packages": [ { "name": "asm89/stack-cors", @@ -11645,7 +11645,448 @@ "time": "2023-04-15T19:07:00+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" + }, + { + "name": "drupal/coder", + "version": "8.3.26", + "source": { + "type": "git", + "url": "https://github.com/pfrenssen/coder.git", + "reference": "fd98546ce3373aa7767240901eda47963ce64c82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pfrenssen/coder/zipball/fd98546ce3373aa7767240901eda47963ce64c82", + "reference": "fd98546ce3373aa7767240901eda47963ce64c82", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1 || ^1.0.0", + "ext-mbstring": "*", + "php": ">=7.2", + "sirbrillig/phpcs-variable-analysis": "^2.11.7", + "slevomat/coding-standard": "^8.11", + "squizlabs/php_codesniffer": "^3.9.1", + "symfony/yaml": ">=3.4.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.7.12", + "phpunit/phpunit": "^8.0" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "Drupal\\": "coder_sniffer/Drupal/", + "DrupalPractice\\": "coder_sniffer/DrupalPractice/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "Coder is a library to review Drupal code.", + "homepage": "https://www.drupal.org/project/coder", + "keywords": [ + "code review", + "phpcs", + "standards" + ], + "support": { + "issues": "https://www.drupal.org/project/issues/coder", + "source": "https://www.drupal.org/project/coder" + }, + "time": "2024-11-28T23:14:29+00:00" + }, + { + "name": "php-parallel-lint/php-parallel-lint", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", + "reference": "6db563514f27e19595a19f45a4bf757b6401194e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6db563514f27e19595a19f45a4bf757b6401194e", + "reference": "6db563514f27e19595a19f45a4bf757b6401194e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.3.0" + }, + "replace": { + "grogy/php-parallel-lint": "*", + "jakub-onderka/php-parallel-lint": "*" + }, + "require-dev": { + "nette/tester": "^1.3 || ^2.0", + "php-parallel-lint/php-console-highlighter": "0.* || ^1.0", + "squizlabs/php_codesniffer": "^3.6" + }, + "suggest": { + "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet" + }, + "bin": [ + "parallel-lint" + ], + "type": "library", + "autoload": { + "classmap": [ + "./src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "ahoj@jakubonderka.cz" + } + ], + "description": "This tool checks the syntax of PHP files about 20x faster than serial check.", + "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", + "keywords": [ + "lint", + "static analysis" + ], + "support": { + "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", + "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.4.0" + }, + "time": "2024-03-27T12:14:49+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.33.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" + }, + "time": "2024-10-13T11:25:22+00:00" + }, + { + "name": "sirbrillig/phpcs-variable-analysis", + "version": "v2.11.21", + "source": { + "type": "git", + "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", + "reference": "eb2b351927098c24860daa7484e290d3eed693be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/eb2b351927098c24860daa7484e290d3eed693be", + "reference": "eb2b351927098c24860daa7484e290d3eed693be", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "squizlabs/php_codesniffer": "^3.5.6" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", + "phpcsstandards/phpcsdevcs": "^1.1", + "phpstan/phpstan": "^1.7", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0 || ^10.5.32 || ^11.3.3", + "sirbrillig/phpcs-import-detection": "^1.1", + "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "VariableAnalysis\\": "VariableAnalysis/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Sam Graham", + "email": "php-codesniffer-variableanalysis@illusori.co.uk" + }, + { + "name": "Payton Swick", + "email": "payton@foolord.com" + } + ], + "description": "A PHPCS sniff to detect problems with variables.", + "keywords": [ + "phpcs", + "static analysis" + ], + "support": { + "issues": "https://github.com/sirbrillig/phpcs-variable-analysis/issues", + "source": "https://github.com/sirbrillig/phpcs-variable-analysis", + "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" + }, + "time": "2024-12-02T16:37:49+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.15.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "7d1d957421618a3803b593ec31ace470177d7817" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", + "reference": "7d1d957421618a3803b593ec31ace470177d7817", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.60", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.16", + "phpstan/phpstan-strict-rules": "1.5.2", + "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2024-03-09T15:20:58+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.11.1", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", + "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-11-16T12:02:36+00:00" + } + ], "aliases": [], "minimum-stability": "dev", "stability-flags": { @@ -11659,7 +12100,7 @@ }, "prefer-stable": true, "prefer-lowest": false, - "platform": {}, - "platform-dev": {}, - "plugin-api-version": "2.6.0" + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.2.0" } From 664ec7a3f6aace627990ae3375950ddb3623d921 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Fri, 6 Dec 2024 17:12:32 -0500 Subject: [PATCH 20/29] USAGOV-2073-published-pages: Only run the exporter if tome finished without an error code. --- scripts/tome-static.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/tome-static.sh b/scripts/tome-static.sh index 050532090b..70d32dad3c 100755 --- a/scripts/tome-static.sh +++ b/scripts/tome-static.sh @@ -34,7 +34,11 @@ time drush tome:static -y --uri=$URI --process-count=$TOME_PROCESS_COUNT --path- TOME_SUCCESS=$? echo "Finished Static Site Generation : "$(date) -# path is relative to drupal's web dir -time drush usapubcsv modules/custom/usagov_ssg_postprocessing/files/published-pages.csv -echo "Exported published-pages.csv" + +if [ "$TOME_SUCCESS" -eq 0 ]; then + # path is relative to drupal's web dir + time drush usapubcsv modules/custom/usagov_ssg_postprocessing/files/published-pages.csv + echo "Exported published-pages.csv" +fi + exit $TOME_SUCCESS From 8f83063eb335ea8743800c68eddc0713762b1602 Mon Sep 17 00:00:00 2001 From: Dale Frey Date: Thu, 12 Dec 2024 12:28:51 -0500 Subject: [PATCH 21/29] USAGOV-150: USAGOV-150 - Increase height of the USWDS Components dialog --- .../custom/usagov/sass/_uswds-theme-custom-styles.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/web/themes/custom/usagov/sass/_uswds-theme-custom-styles.scss b/web/themes/custom/usagov/sass/_uswds-theme-custom-styles.scss index 2db0e78830..971137b756 100644 --- a/web/themes/custom/usagov/sass/_uswds-theme-custom-styles.scss +++ b/web/themes/custom/usagov/sass/_uswds-theme-custom-styles.scss @@ -924,3 +924,12 @@ input::-webkit-textfield-decoration-container { max-width: 100%; } } + +/* Dialog sizing code for USAGOV-150 */ +.ui-dialog.ckeditor5-paragraph-embed-modal { + top: 5vh !important; + min-height: 80vh !important; +} +.ui-dialog.ckeditor5-paragraph-embed-modal > .ui-dialog-content { + height: 80vh !important; +} From e89bf396c5e6a9e5d756e3c25a8092a4bf0d96ee Mon Sep 17 00:00:00 2001 From: Amy Farrell Date: Thu, 12 Dec 2024 16:05:25 -0800 Subject: [PATCH 22/29] USAGOV-2078-restore-newrelic: Correct the path to newrelic.ini --- bin/src/newrelic.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/src/newrelic.sh b/bin/src/newrelic.sh index 4f7ed5a00f..28d0dac447 100755 --- a/bin/src/newrelic.sh +++ b/bin/src/newrelic.sh @@ -29,7 +29,7 @@ if [ "$(uname -m)" != 'aarch64' ]; then -e 's/;\?newrelic.loglevel =.*/newrelic.loglevel = "info"/' \ -e 's/;\?newrelic.enabled =.*/newrelic.enabled = false/' \ -e 's/;\?newrelic.error_collector.record_database_errors =.*/newrelic.error_collector.record_database_errors = true/' \ - /etc/php81/conf.d/newrelic.ini + /etc/php83/conf.d/newrelic.ini NR_LATEST_VERSION="$(curl -sS https://download.newrelic.com/php_agent/release/ | sed -n 's/.*>\(.*linux\-musl\).tar.gz<.*/\1/p')" export NR_LATEST_VERSION From 6e46df7625b8efb9e818dd10590aa4597acc5f6b Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 16 Dec 2024 10:41:29 -0500 Subject: [PATCH 23/29] USAGOV-2117-phpcs-local: Removing stray words --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 46ff6b8152..1edf9ff9e4 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,7 @@ If you make any changes to the `scss` or `js` files, make sure to check for lint PHPCodesniffer and the parallel linting tools should be installed automatically on a local environment via `composer install`. PHPCodeSniffer is used to ensure new code follows Drupal's coding standard. The parallel linter will check for PHP syntax errors. If they detect any errors, they must be fixed before a PR of changes can be accepted. -The following composer scripts are aliases for running these tools. development setup +The following composer scripts are aliases for running these tools. * Check for code style errors across all project files. Must have zero errors: `./bin/composer phpcs-errors`: @@ -337,8 +337,6 @@ The following composer scripts are aliases for running these tools. development * Check for PHP lint errors `./bin/composer php-lint` - - ## Project Restart/Reset Sometimes, Docker problems arise after an upgrade and a more complete restart is needed. After closing down and destroying the existing containers, networks, and volumes the procedure is the same as the full project setup. From d1023120c0da8179fb79e2772f038cca901059d4 Mon Sep 17 00:00:00 2001 From: Jacob Yeager Date: Mon, 16 Dec 2024 10:43:38 -0500 Subject: [PATCH 24/29] dev: adding conveince script for composer --- bin/composer-reqs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 bin/composer-reqs diff --git a/bin/composer-reqs b/bin/composer-reqs new file mode 100755 index 0000000000..aa4fc8c6a8 --- /dev/null +++ b/bin/composer-reqs @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +docker compose run \ + --rm \ + --no-deps \ + --workdir /var/www \ + composer \ + composer "$@" From d33f871d43c69fcd660fef95b50928902405242b Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 16 Dec 2024 13:20:15 -0500 Subject: [PATCH 25/29] USAGOV-2073-published-pages: Adding comments to explain listener and output. --- .../src/EventSubscriber/DatalayerAlterSubscriber.php | 2 ++ .../usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php b/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php index 9ec8f030c7..8c7555faa0 100644 --- a/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php +++ b/web/modules/custom/usagov_benefit_category_search/src/EventSubscriber/DatalayerAlterSubscriber.php @@ -26,6 +26,8 @@ public static function getSubscribedEvents() { */ public function onDatalayerAlter(DatalayerAlterEvent $event): void { + // This listener is only interested in nodes, which have numeric IDs. + // Taxonomy terms IDs are prefixed with "t_" if (!isset($event->datalayer['nodeID']) || !is_numeric($event->datalayer['nodeID'])) { return; } diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index 6e2aceaac7..4f8c6d1696 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -28,6 +28,8 @@ public function __construct( public readonly string $pageTitle, // complete URL including domain name public readonly string $fullURL, + // We call the pages and URLs here "Taxonomy" but they aren't Drupal taxonomy terms. + // The following properties come from home page + menu-driven breadcrumbs. public readonly string $taxonomyText1, public readonly string $taxonomyText2, public readonly string $taxonomyText3, From e9d5810ca15b64496575f57b7c1e7a0edc2dc8c4 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 16 Dec 2024 13:48:44 -0500 Subject: [PATCH 26/29] USAGOV-2073-published-pages: Add URI param to CSV export so it builds URLs using the same hostname as tome script. --- scripts/tome-static.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tome-static.sh b/scripts/tome-static.sh index 70d32dad3c..4b4f4dd61d 100755 --- a/scripts/tome-static.sh +++ b/scripts/tome-static.sh @@ -37,7 +37,7 @@ echo "Finished Static Site Generation : "$(date) if [ "$TOME_SUCCESS" -eq 0 ]; then # path is relative to drupal's web dir - time drush usapubcsv modules/custom/usagov_ssg_postprocessing/files/published-pages.csv + time drush usapubcsv --uri=$URI modules/custom/usagov_ssg_postprocessing/files/published-pages.csv echo "Exported published-pages.csv" fi From 8886dad461d02986782f88cc347dc23c345c6d58 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 16 Dec 2024 15:44:59 -0500 Subject: [PATCH 27/29] USAGOV-2073-published-pages: Add acronym to federal agency titles to match previous versions of CSV. --- .../src/Data/PublishedPagesRow.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index 4f8c6d1696..06f4c51de8 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -99,6 +99,15 @@ public function toArray(): array { public static function datalayerForNode(array $data, Node $node, string $baseURL): self { $title = $node->getTitle(); + // Federal Agency nodes tack on the acronym because the original implementation + // pulled the title from the HTML + if ($node->getType() === 'directory_record') { + $acronym = $node->get('field_acronym')->getValue(); + if ($acronym) { + $title = sprintf("%s (%s)", $title, $acronym[0]['value']); + } + } + if ($data['homepageTest'] === 'homepage' && $data['language'] === 'en') { $friendlyURL = TaxonomyDatalayerBuilder::HOME_URL_EN; $fullURL = $baseURL . TaxonomyDatalayerBuilder::HOME_URL_EN; From 9b6b15b36f650cdbbb2ad1b6a9c3775cbba40a99 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Mon, 16 Dec 2024 17:23:45 -0500 Subject: [PATCH 28/29] USAGOV-2073-published-pages: Trim to clean up agency titles. --- .../src/Data/PublishedPagesRow.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index 06f4c51de8..e841b85d53 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -104,7 +104,7 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL if ($node->getType() === 'directory_record') { $acronym = $node->get('field_acronym')->getValue(); if ($acronym) { - $title = sprintf("%s (%s)", $title, $acronym[0]['value']); + $title = sprintf("%s (%s)", trim($title), trim($acronym[0]['value'])); } } @@ -175,7 +175,11 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL } public static function datalayerForWizard(array $data, Term $term, string $baseURL): self { - $title = $term->getName(); + if ($heading = $term->get('field_heading')->getValue()) { + $title = $heading[0]['value']; + } else { + $title = $term->getName(); + } $friendlyURL = $term->toUrl('canonical', options: ['language' => $term->language()] From c8b5429af7067e0ac67c3c003e0df53ec0e4d434 Mon Sep 17 00:00:00 2001 From: OscarMerida Date: Tue, 17 Dec 2024 09:41:50 -0500 Subject: [PATCH 29/29] USAGOV-2073-published-pages: Clean up code style. --- .../usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php index e841b85d53..7ff92993bf 100644 --- a/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php +++ b/web/modules/custom/usagov_ssg_postprocessing/src/Data/PublishedPagesRow.php @@ -177,7 +177,8 @@ public static function datalayerForNode(array $data, Node $node, string $baseURL public static function datalayerForWizard(array $data, Term $term, string $baseURL): self { if ($heading = $term->get('field_heading')->getValue()) { $title = $heading[0]['value']; - } else { + } + else { $title = $term->getName(); }