Commit 4f31ea82 authored by Fran Garcia-Linares's avatar Fran Garcia-Linares Committed by Tim Plunkett
Browse files

Issue #3279663 by fjgarlin, chrisfromredfin: Caching of results and validation of parameters

parent 4700b118
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -12,3 +12,9 @@ services:
    class: '\Drupal\project_browser\EventSubscriber\UpdateFixtureSubscriber'
    tags:
      - { name: 'event_subscriber' }
  cache.project_browser:
    class: Drupal\Core\Cache\CacheBackendInterface
    tags:
      - { name: cache.bin }
    factory: cache_factory:get
    arguments: [project_browser]
+84 −7
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

namespace Drupal\project_browser\Controller;

use Drupal\Component\Utility\Xss;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\project_browser\EnabledSourceHandler;
@@ -22,6 +23,13 @@ class ProjectBrowserEndpointController extends ControllerBase {
   */
  protected $enabledSource;

  /**
   * ProjectBrowser cache bin.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cacheBin;

  /**
   * ProjectBrowserEndpointController constructor.
   *
@@ -30,6 +38,15 @@ class ProjectBrowserEndpointController extends ControllerBase {
   */
  public function __construct(EnabledSourceHandler $enabled_source) {
    $this->enabledSource = $enabled_source;
    $this->cacheBin = $this->cache('project_browser');

    $plugin_id = $this->enabledSource->getCurrentSource()->getPluginId();
    $cache_key = 'project_browser:enabled_source';
    $cached_enabled_source = $this->cacheBin->get($cache_key);
    if ($cached_enabled_source === FALSE || ($cached_enabled_source->data != $plugin_id)) {
      $this->cacheBin->deleteAll();
      $this->cacheBin->set($cache_key, $plugin_id);
    }
  }

  /**
@@ -57,8 +74,53 @@ class ProjectBrowserEndpointController extends ControllerBase {
    if (!$current_source) {
      return new JsonResponse([], Response::HTTP_ACCEPTED);
    }
    $all_projects = $current_source->getProjects($request->query->all());
    return new JsonResponse($all_projects);

    // Validate and build query.
    $direction = $request->query->get('direction');
    $query = [
      // Page and limit are checked against a valid list in in_array, below.
      'page' => (int) $request->query->get('page', 0),
      'limit' => (int) $request->query->get('limit', 12),
      'sort' => Xss::filter($request->query->get('sort')),
      'direction' => in_array($direction, ['ASC', 'DESC']) ? $direction : 'ASC',
    ];

    $title = $request->query->get('search', NULL);
    if ($title) {
      $query['search'] = Xss::filter($title);
    }

    $categories = $request->query->get('categories', NULL);
    if ($categories) {
      $query['categories'] = Xss::filter($categories);
    }

    $maintenance_status = $request->query->get('maintenance_status', NULL);
    if ($maintenance_status) {
      $query['maintenance_status'] = Xss::filter($maintenance_status);
    }

    $development_status = $request->query->get('development_status', NULL);
    if ($development_status) {
      $query['development_status'] = Xss::filter($development_status);
    }

    $security_advisory_coverage = $request->query->get('security_advisory_coverage', NULL);
    if ($security_advisory_coverage) {
      $query['security_advisory_coverage'] = Xss::filter($security_advisory_coverage);
    }

    // Cache only exact query, down to the page number.
    $cache_key = 'project_browser:projects:' . md5(json_encode($query));
    if ($projects = $this->cacheBin->get($cache_key)) {
      $projects = $projects->data;
    }
    else {
      $projects = $current_source->getProjects($query);
      $this->cacheBin->set($cache_key, $projects);
    }

    return new JsonResponse($projects);
  }

  /**
@@ -75,11 +137,18 @@ class ProjectBrowserEndpointController extends ControllerBase {
      return new JsonResponse([], Response::HTTP_ACCEPTED);
    }

    $project = $request->query->get('project');
    $project = Xss::filter($request->query->get('project'));
    if ($project) {
      $cache_key = 'project_browser:releases:' . $project;
      if ($releases = $this->cacheBin->get($cache_key)) {
        $releases = $releases->data;
      }
      else {
        $releases = $current_source->getProjectReleases($project);
        $this->cacheBin->set($cache_key, $releases);
      }
      if (count($releases)) {
        $response = new JsonResponse((array) $releases, Response::HTTP_ACCEPTED);
        $response = new JsonResponse((array) $releases);
        if ($response instanceof CacheableResponseInterface) {
          $response->addCacheableDependency($releases);
        }
@@ -103,8 +172,16 @@ class ProjectBrowserEndpointController extends ControllerBase {
      return new JsonResponse([], Response::HTTP_ACCEPTED);
    }

    $cache_key = 'project_browser:categories';
    if ($categories = $this->cacheBin->get($cache_key)) {
      $categories = $categories->data;
    }
    else {
      $categories = $current_source->getCategories();
    return new JsonResponse($categories, Response::HTTP_ACCEPTED);
      $this->cacheBin->set($cache_key, $categories);
    }

    return new JsonResponse($categories);
  }

}
+11 −13
Original line number Diff line number Diff line
@@ -144,15 +144,13 @@ class MockDrupalDotOrg extends PluginBase implements ProjectBrowserSourceInterfa
  public function getProjects(array $query = []) : ProjectsResultsPage {
    $api_response = $this->fetchProjects($query);

    // Iterate through and turn each into a
    // \Drupal\project_browser\ProjectBrowser\Project.
    $returned_list = [];
    if ($api_response) {
      foreach ($api_response['list'] as $project) {
        if (is_object($project)) {
          $project = (array) $project;
        }
        // @todo Map any properties from the mock to the expected in Project.
        // Map any properties from the mock to the expected in Project.
        $project['field_maintenance_status'] = $project['taxonomy_vocabulary_44'];
        $project['field_module_categories'] = $project['taxonomy_vocabulary_3'];
        $project['field_development_status'] = $project['taxonomy_vocabulary_46'];
@@ -187,26 +185,26 @@ class MockDrupalDotOrg extends PluginBase implements ProjectBrowserSourceInterfa
      }

      // Filter by maintenance status.
      if (array_key_exists('field_maintenance_status', $query)) {
        $tids = explode(',', $query['field_maintenance_status']);
      if (array_key_exists('maintenance_status', $query)) {
        $tids = explode(',', $query['maintenance_status']);
        $db_query->condition('maintenance_status', $tids, 'IN');
      }

      // Filter by development status.
      if (array_key_exists('field_development_status', $query)) {
        $tids = explode(',', $query['field_development_status']);
      if (array_key_exists('development_status', $query)) {
        $tids = explode(',', $query['development_status']);
        $db_query->condition('development_status', $tids, 'IN');
      }

      // Filter by security advisory coverage.
      if (array_key_exists('field_security_advisory_coverage', $query)) {
        $tids = explode(',', $query['field_security_advisory_coverage']);
      if (array_key_exists('security_advisory_coverage', $query)) {
        $tids = explode(',', $query['security_advisory_coverage']);
        $db_query->condition('field_security_advisory_coverage', $tids, 'IN');
      }

      // Filter by category.
      if (array_key_exists('field_module_categories', $query)) {
        $tids = explode(',', $query['field_module_categories']);
      if (array_key_exists('categories', $query)) {
        $tids = explode(',', $query['categories']);
        if (count($tids) === 1) {
          $db_query->join('project_browser_categories', 'cat', 'pbp.nid = cat.pid AND cat.tid = :tid', [
            ':tid' => $tids[0],
@@ -227,8 +225,8 @@ class MockDrupalDotOrg extends PluginBase implements ProjectBrowserSourceInterfa
      }

      // Filter by search term.
      if (array_key_exists('title', $query)) {
        $title = $query['title'];
      if (array_key_exists('search', $query)) {
        $title = $query['search'];
        $db_query->condition('pbp.title', "%$title%", 'LIKE');
      }

+11 −0
Original line number Diff line number Diff line
@@ -20,6 +20,17 @@ interface ProjectBrowserSourceInterface {
   * @param array $query
   *   The query string params from the frontend request.
   *
   *   The expected parameters will be:
   *   - page: Page number.
   *   - limit: Number of elements per page.
   *   - sort: Field to do the sorting on.
   *   - direction: 'ASC' or 'DESC'.
   *   - search: Search term.
   *   - categories: Comma separated list of term names or IDs.
   *   - maintenance_status: Comma separated list of term names or IDs.
   *   - development_status: Comma separated list of term names or IDs.
   *   - security_advisory_coverage: Comma separated list of term names or IDs.
   *
   * @return \Drupal\project_browser\ProjectBrowser\ProjectsResultsPage
   *   Returns a \Drupal\project_browser\ProjectBrowser\ProjectsResultsPage
   */
+0 −0

File changed.

Preview suppressed by a .gitattributes entry or the file's encoding is unsupported.

Loading