From 01029b35b6fde95813e297c0562cacbb6fe27d6c Mon Sep 17 00:00:00 2001
From: Artem  Dmitriiev <a.dmitriiev@1xinternet.de>
Date: Wed, 12 Mar 2025 12:24:13 +0100
Subject: [PATCH 1/4] Issue #3512440 by a.dmitriiev: Support project browser
 2.0

---
 composer.json                              |  3 ++-
 src/Plugin/ProjectBrowserSource/Gitlab.php | 24 ++++++----------------
 2 files changed, 8 insertions(+), 19 deletions(-)

diff --git a/composer.json b/composer.json
index ab09267..9b24499 100644
--- a/composer.json
+++ b/composer.json
@@ -13,6 +13,7 @@
         }
     ],
     "require": {
-        "drupal/core": "^10.3 || ^11.1"
+        "drupal/core": "^10.3 || ^11.1",
+        "drupal/project_browser": "^2.0"
     }
 }
diff --git a/src/Plugin/ProjectBrowserSource/Gitlab.php b/src/Plugin/ProjectBrowserSource/Gitlab.php
index dd7a61a..cb4fafd 100644
--- a/src/Plugin/ProjectBrowserSource/Gitlab.php
+++ b/src/Plugin/ProjectBrowserSource/Gitlab.php
@@ -4,6 +4,7 @@ namespace Drupal\project_browser_gitlab\Plugin\ProjectBrowserSource;
 
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Url;
 use Drupal\project_browser\Plugin\ProjectBrowserSourceBase;
 use Drupal\project_browser\ProjectBrowser\Project;
 use Drupal\project_browser\ProjectBrowser\ProjectsResultsPage;
@@ -161,14 +162,13 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
       }
 
       $projects[] = new Project(
-        logo: $logo,
+        logo: $logo['file']['uri'] ? Url::fromUri($logo['file']['uri']) : NULL,
         isCompatible: TRUE,
         isCovered: TRUE,
         projectUsageTotal: 0,
         machineName: str_replace('/', '|', $project['path_with_namespace']),
         body: $project['description'] ? ['value' => $project['description']] : [],
         title: $project['name'] ?? '',
-        author: [],
         packageName: $project['path_with_namespace'],
         categories: $categories,
         type: ProjectType::Module,
@@ -255,22 +255,10 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
    */
   public function getSortOptions(): array {
     return [
-      'created' => [
-        'id' => 'created',
-        'text' => $this->t('Newest First'),
-      ],
-      'a_z' => [
-        'id' => 'a_z',
-        'text' => $this->t('A-Z'),
-      ],
-      'z_a' => [
-        'id' => 'z_a',
-        'text' => $this->t('Z-A'),
-      ],
-      'updated' => [
-        'id' => 'updated',
-        'text' => $this->t('Latest Updated First'),
-      ],
+      'created' => $this->t('Newest First'),
+      'a_z' => $this->t('A-Z'),
+      'z_a' => $this->t('Z-A'),
+      'updated' => $this->t('Latest Updated First'),
     ];
   }
 
-- 
GitLab


From 38545c8d2d121b7e28e9fd06e809a4cc7264c056 Mon Sep 17 00:00:00 2001
From: Artem  Dmitriiev <a.dmitriiev@1xinternet.de>
Date: Wed, 12 Mar 2025 14:46:17 +0100
Subject: [PATCH 2/4] Populate also images array

---
 src/Plugin/ProjectBrowserSource/Gitlab.php | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/src/Plugin/ProjectBrowserSource/Gitlab.php b/src/Plugin/ProjectBrowserSource/Gitlab.php
index cb4fafd..bba7072 100644
--- a/src/Plugin/ProjectBrowserSource/Gitlab.php
+++ b/src/Plugin/ProjectBrowserSource/Gitlab.php
@@ -143,15 +143,16 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
     }
 
     foreach ($response['data'] ?? [] as $project) {
-      $logo = [
-        'file' => [
-          'uri' => $project['avatar_url'],
-          'resource' => 'image',
-        ],
-        'alt' => (string) $this->t('@name logo', [
-          '@name' => $project['name'],
-        ]),
-      ];
+      $images = [];
+      if (!empty($project['avatar_url'])) {
+        $logo = [
+          'file' => Url::fromUri($project['avatar_url']),
+          'alt' => (string) $this->t('@name logo', [
+            '@name' => $project['name'],
+          ]),
+        ];
+        $images[] = $logo;
+      }
 
       $categories = [];
       foreach ($project['topics'] as $index => $topic) {
@@ -162,7 +163,7 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
       }
 
       $projects[] = new Project(
-        logo: $logo['file']['uri'] ? Url::fromUri($logo['file']['uri']) : NULL,
+        logo: $logo ? $logo['file'] : NULL,
         isCompatible: TRUE,
         isCovered: TRUE,
         projectUsageTotal: 0,
@@ -172,6 +173,7 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
         packageName: $project['path_with_namespace'],
         categories: $categories,
         type: ProjectType::Module,
+        images: $images,
       );
     }
 
-- 
GitLab


From 4b5a5d93b4235d1166daaaf66d08f2afb2b818b2 Mon Sep 17 00:00:00 2001
From: Artem  Dmitriiev <a.dmitriiev@1xinternet.de>
Date: Wed, 12 Mar 2025 15:22:25 +0100
Subject: [PATCH 3/4] Add event to allow other modules to modify the project
 info

---
 src/Event/ProjectEvent.php                 | 74 ++++++++++++++++++++++
 src/Plugin/ProjectBrowserSource/Gitlab.php | 44 ++++++++-----
 2 files changed, 102 insertions(+), 16 deletions(-)
 create mode 100644 src/Event/ProjectEvent.php

diff --git a/src/Event/ProjectEvent.php b/src/Event/ProjectEvent.php
new file mode 100644
index 0000000..549a4a9
--- /dev/null
+++ b/src/Event/ProjectEvent.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Drupal\project_browser_gitlab\Event;
+
+use Drupal\Component\EventDispatcher\Event;
+use Drupal\project_browser_gitlab\GitlabSourceInterface;
+
+/**
+ * Class for project event to modify the information from Gitlab API if needed.
+ */
+class ProjectEvent extends Event {
+
+  /**
+   * The project info from Gitlab.
+   *
+   * @var array
+   */
+  protected $project;
+
+  /**
+   * The gitlab source.
+   *
+   * @var \Drupal\project_browser_gitlab\GitlabSourceInterface
+   */
+  protected GitlabSourceInterface $gitlabSource;
+
+  /**
+   * Constructs the event object.
+   *
+   * @param array $project
+   *   The project info from Gitlab API response.
+   * @param \Drupal\project_browser_gitlab\GitlabSourceInterface $gitlab_source
+   *   The Gitlab Source entity.
+   */
+  public function __construct(array $project, GitlabSourceInterface $gitlab_source) {
+    $this->project = $project;
+    $this->gitlabSource = $gitlab_source;
+  }
+
+  /**
+   * Gets the project info.
+   *
+   * @return array
+   *   The project info.
+   */
+  public function getProject() {
+    return $this->project;
+  }
+
+  /**
+   * Gets the Gitlab Source entity.
+   *
+   * @return \Drupal\project_browser_gitlab\GitlabSourceInterface
+   *   The Gitlab Source entity.
+   */
+  public function getGitlabSource() {
+    return $this->gitlabSource;
+  }
+
+  /**
+   * Sets the project.
+   *
+   * @param array $project
+   *   The modified project.
+   *
+   * @return self
+   *   The event object.
+   */
+  public function setProject(array $project) {
+    $this->project = $project;
+    return $this;
+  }
+
+}
diff --git a/src/Plugin/ProjectBrowserSource/Gitlab.php b/src/Plugin/ProjectBrowserSource/Gitlab.php
index bba7072..b858096 100644
--- a/src/Plugin/ProjectBrowserSource/Gitlab.php
+++ b/src/Plugin/ProjectBrowserSource/Gitlab.php
@@ -10,10 +10,12 @@ use Drupal\project_browser\ProjectBrowser\Project;
 use Drupal\project_browser\ProjectBrowser\ProjectsResultsPage;
 use Drupal\project_browser\ProjectType;
 use Drupal\project_browser_gitlab\Entity\GitlabSource;
+use Drupal\project_browser_gitlab\Event\ProjectEvent;
 use GuzzleHttp\ClientInterface;
 use GuzzleHttp\Exception\GuzzleException;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Project Browser Source Plugin for Gitlab.
@@ -48,6 +50,13 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
    */
   protected GitlabSource $source;
 
+  /**
+   * The event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected EventDispatcherInterface $eventDispatcher;
+
   /**
    * Constructor for the plugin.
    *
@@ -60,15 +69,21 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
    * @param \GuzzleHttp\ClientInterface $httpClient
    *   The HTTP client.
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *  The entity type manager.
+   *   The entity type manager.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
+   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, ClientInterface $httpClient, EntityTypeManagerInterface $entity_type_manager, LoggerInterface $logger) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, ClientInterface $httpClient, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $event_dispatcher, LoggerInterface $logger) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->httpClient = $httpClient;
     $this->logger = $logger;
     $this->source = $entity_type_manager->getStorage('project_browser_gitlab_source')->load($plugin_definition['id']);
+    $this->eventDispatcher = $event_dispatcher;
   }
 
   /**
@@ -81,11 +96,11 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
       $plugin_definition,
       $container->get('http_client'),
       $container->get('entity_type.manager'),
+      $container->get('event_dispatcher'),
       $container->get('logger.factory')->get('project_browser'),
     );
   }
 
-
   /**
    * {@inheritdoc}
    * @param array $query
@@ -143,15 +158,14 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
     }
 
     foreach ($response['data'] ?? [] as $project) {
-      $images = [];
+      $project['type'] = ProjectType::Module;
+      // Allow other modules to modify the project info.
+      $event = new ProjectEvent($project, $this->source);
+      $this->eventDispatcher->dispatch($event);
+      $project = $event->getProject();
+      $logo = NULL;
       if (!empty($project['avatar_url'])) {
-        $logo = [
-          'file' => Url::fromUri($project['avatar_url']),
-          'alt' => (string) $this->t('@name logo', [
-            '@name' => $project['name'],
-          ]),
-        ];
-        $images[] = $logo;
+        $logo = Url::fromUri($project['avatar_url']);
       }
 
       $categories = [];
@@ -161,19 +175,17 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
           'name' => $topic,
         ];
       }
-
       $projects[] = new Project(
-        logo: $logo ? $logo['file'] : NULL,
+        logo: $logo,
         isCompatible: TRUE,
         isCovered: TRUE,
         projectUsageTotal: 0,
-        machineName: str_replace('/', '|', $project['path_with_namespace']),
+        machineName: $project['path'],
         body: $project['description'] ? ['value' => $project['description']] : [],
         title: $project['name'] ?? '',
         packageName: $project['path_with_namespace'],
         categories: $categories,
-        type: ProjectType::Module,
-        images: $images,
+        type: $project['type'],
       );
     }
 
-- 
GitLab


From ffce35358711061175c410dcf302dd70728dcc17 Mon Sep 17 00:00:00 2001
From: Artem  Dmitriiev <a.dmitriiev@1xinternet.de>
Date: Wed, 9 Apr 2025 17:58:02 +0200
Subject: [PATCH 4/4] Compatibility with project_browser 2.0.0-beta1

---
 src/Plugin/ProjectBrowserSource/Gitlab.php | 38 +++++++++++++++-------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/src/Plugin/ProjectBrowserSource/Gitlab.php b/src/Plugin/ProjectBrowserSource/Gitlab.php
index b858096..6e8d80f 100644
--- a/src/Plugin/ProjectBrowserSource/Gitlab.php
+++ b/src/Plugin/ProjectBrowserSource/Gitlab.php
@@ -4,8 +4,12 @@ namespace Drupal\project_browser_gitlab\Plugin\ProjectBrowserSource;
 
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\project_browser\Attribute\ProjectBrowserSource;
 use Drupal\project_browser\Plugin\ProjectBrowserSourceBase;
+use Drupal\project_browser\ProjectBrowser\Filter\MultipleChoiceFilter;
+use Drupal\project_browser\ProjectBrowser\Filter\TextFilter;
 use Drupal\project_browser\ProjectBrowser\Project;
 use Drupal\project_browser\ProjectBrowser\ProjectsResultsPage;
 use Drupal\project_browser\ProjectType;
@@ -19,14 +23,13 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Project Browser Source Plugin for Gitlab.
- *
- * @ProjectBrowserSource(
- *   id = "project_browser_gitlab",
- *   label = @Translation("Gitlab"),
- *   description = @Translation("Source plugin for Project Browser to search Gitlab."),
- *   deriver = "Drupal\project_browser_gitlab\Plugin\Derivative\GitlabDeriver",
- * )
  */
+#[ProjectBrowserSource(
+  id: 'project_browser_gitlab',
+  label: new TranslatableMarkup('Gitlab'),
+  description: new TranslatableMarkup('Source plugin for Project Browser to search Gitlab.'),
+  deriver: 'Drupal\project_browser_gitlab\Plugin\Derivative\GitlabDeriver',
+)]
 class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginInterface {
 
   /**
@@ -210,13 +213,10 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
 
     $categories = [];
     foreach ($response['data'] ?? [] as $category) {
-      $categories[$category['name']] = [
-        'id' => $category['name'],
-        'name' => $category['name'],
-      ];
+      $categories[$category['name']] = $category['name'];
     }
 
-    return array_values($categories);
+    return $categories;
   }
 
   /**
@@ -276,4 +276,18 @@ class Gitlab extends ProjectBrowserSourceBase implements ContainerFactoryPluginI
     ];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getFilterDefinitions(): array {
+    $filters = [];
+    $filters['search'] = new TextFilter('', $this->t('Search'));
+    $filters['categories'] = new MultipleChoiceFilter(
+      $this->getCategories(),
+      [],
+      $this->t('Categories'),
+    );
+    return $filters;
+  }
+
 }
-- 
GitLab