diff --git a/cloudflare.services.yml b/cloudflare.services.yml index 7e16b4c..4e419db 100644 --- a/cloudflare.services.yml +++ b/cloudflare.services.yml @@ -11,3 +11,8 @@ services: arguments: ['%cloudflare.cache_tag_header_limit%'] tags: - { name: event_subscriber } + cloudflare: + class: Drupal\cloudflare\CloudFlareService + arguments: ['@config.factory'] + tags: + - { name: cloudflare} diff --git a/src/CloudFlareService.php b/src/CloudFlareService.php new file mode 100644 index 0000000..6d67cec --- /dev/null +++ b/src/CloudFlareService.php @@ -0,0 +1,191 @@ +config = $config->get('cloudflare.settings'); + $this->api_key = $config->get('apikey'); + $this->email = $config->get('email'); + + if ($this->hasValidApiCredentials()) { + $this->zone = $this->getCurrentZoneId(); + } + } + + /** + * Invalidates tags at CloudFlare edge. + * + * @param array $tags + * String array of tag names to invalidate. + */ + public function invalidateByTags(array $tags) { + if (!$this->hasValidApiCredentials()) { + return; + } + + try { + $this->zoneApi = new ZoneApi($this->apiKey, $this->email); + $this->zoneApi->purgeTags($this->zone, $tags); + } + + catch (CloudFlareHttpException $e) { + drupal_set_message("Unable to clear zone cache. " . $e->getMessage(), 'error'); + \Drupal::logger('cloudflare')->error($e->getMessage()); + return; + } + + catch (CloudFlareApiException $e) { + drupal_set_message("Unable to clear zone cache. " . $e->getMessage(), 'error'); + \Drupal::logger('cloudflare')->error($e->getMessage()); + return; + } + + // If no exceptions have been thrown then the request has been successful. + } + + /** + * Invalidates paths at CloudFlare edge. + * + * @param array $paths + * String array of paths to invalidate. + */ + public function invalidateByPath(array $paths) { + if (!$this->hasValidApiCredentials()) { + return; + } + + try { + $this->zoneApi = new ZoneApi($this->apiKey, $this->email); + $this->zoneApi->purgeIndividualFiles($this->zone, $paths); + } + + catch (CloudFlareHttpException $e) { + drupal_set_message("Unable to clear zone cache. " . $e->getMessage(), 'error'); + \Drupal::logger('cloudflare')->error($e->getMessage()); + return; + } + + catch (CloudFlareApiException $e) { + drupal_set_message("Unable to clear zone cache. " . $e->getMessage(), 'error'); + \Drupal::logger('cloudflare')->error($e->getMessage()); + return; + } + } + + /** + * Invalidates entire zone at CloudFlare edge. Use cautiously. + */ + public function invalidateZone() { + if (!$this->hasValidApiCredentials()) { + return; + } + + try { + $this->zoneApi = new ZoneApi($this->apiKey, $this->email); + $this->zoneApi->purgeAllFiles($this->zone); + } + + catch (CloudFlareHttpException $e) { + drupal_set_message("Unable to clear zone cache. " . $e->getMessage(), 'error'); + \Drupal::logger('cloudflare')->error($e->getMessage()); + return; + } + + catch (CloudFlareApiException $e) { + drupal_set_message("Unable to clear zone cache. " . $e->getMessage(), 'error'); + \Drupal::logger('cloudflare')->error($e->getMessage()); + return; + } + } + + /** + * Determine the current Cloudflare ZoneId for the site. + * + * Most CloudFlare accounts have a single zone. It can be assumed as the + * default. If there is more than one the user needs to specify the zone. + * on the cloudflare config page. + * + * @return string + * The id of the current zone. + */ + public function getCurrentZoneId() { + $has_zone_in_cmi = !is_null($this->config->get('zone')); + + // If this is a multi-zone cloudflare account and a zone has been set. + if ($has_zone_in_cmi) { + return $this->config->get('zone'); + } + + // If there is no zone set and the account only has a single zone. + $zones_from_api = $this->zoneApi->listZones(); + $num_zones_from_api = count($zones_from_api); + $is_single_zone_cloudflare_account = $num_zones_from_api == 1; + if ($is_single_zone_cloudflare_account) { + return $zones_from_api[0]->getZoneId(); + } + + // If the zone has multiple accounts and none is specified in CMI we cannot + // move forward. + if (!$is_single_zone_cloudflare_account) { + $link_to_settings = '/admin/config/services/cloudflare/zone'; + $message = t('No default zone has been entered for CloudFlare. Please go here to set.', ['@link_to_settings' => $link_to_settings]); + + drupal_set_message($message, 'error'); + \Drupal::logger('cloudflare')->error($message); + } + } + + /** + * Checks if the site has valid CloudFlare Api credentials. + */ + private function hasValidApiCredentials() { + if (!isset($this->apiKey)) { + $link_to_settings = '/admin/config/services/cloudflare'; + $message = t('No valid credentials have been entered for CloudFlare. Please go here to set them.', ['@link_to_settings' => $link_to_settings]); + + drupal_set_message($message, 'error'); + \Drupal::logger('cloudflare')->error($message); + return FALSE; + } + + return TRUE; + } + +}