You are here

mollie_payment.installer.inc in Mollie Payment 7.2

File

includes/mollie_payment.installer.inc
View source
<?php

namespace Drupal\mollie_payment;

use MolliePaymentMethodController;

/**
 * Class MolliePaymentInstaller.
 *
 * @package Drupal\mollie_payment
 */
class MolliePaymentInstaller {

  // Define constants for this class.
  const LIBRARY_NAME = 'mollie-api-php';
  const MOLLIE_API_CLIENT_URL = 'https://api.github.com/repos/mollie/mollie-api-php/releases/latest';
  const MOLLIE_API_KEYS_URL = 'https://www.mollie.com/dashboard/developers/api-keys';
  const MOLLIE_TOKENS_URL = 'https://www.mollie.com/dashboard/developers/organization-access-tokens';
  const MOLLIE_CREATE_ACCOUNT_URL = 'https://www.mollie.com/dashboard/signup/958337';
  const MOLLIE_ACCOUNT_URL = 'https://www.mollie.com/dashboard/login';

  /**
   * Checks if the Mollie API client for PHP is installed.
   *
   * @return array
   *   An associative array as expected by hook_requirements().
   */
  public function checkMollieApiClient() {

    // Default requirements info.
    $value = 'not found';
    $description = t('The Mollie API client for PHP is missing.');
    $severity = REQUIREMENT_WARNING;

    // Try to detect the installation state of the Mollie API client for PHP.
    $library = libraries_detect(self::LIBRARY_NAME);
    if ($library) {
      if ($library['installed']) {

        // The client is installed. Show the installed version.
        $value = $library['version'];
        $description = t('Version @version of the Mollie API client for PHP is installed.', array(
          '@version' => $library['version'],
        ));
        $severity = REQUIREMENT_OK;
      }
      else {

        // The client is not installed. Show the error and error message.
        $value = $library['error'];
        $description = $library['error message'];

        // Add a link to the client installer.
        $description .= ' ' . t('Click to <a href="!url">install the Mollie API client for PHP</a>.', array(
          '!url' => url('admin/config/services/mollie/client-installer', array(
            'query' => array(
              'destination' => current_path(),
            ),
          )),
        ));
      }
    }
    return $this
      ->formatRequirements('Mollie API client for PHP', $value, $description, $severity);
  }

  /**
   * Checks if a Mollie account has been configured.
   *
   * @return array
   *   An associative array as expected by hook_requirements().
   */
  public function checkMollieAccount() {
    $value = 'no API key';
    $description = t('There is no default live API key configured.');
    $url = url('admin/config/services/mollie/account');
    $severity = REQUIREMENT_WARNING;
    $apiKey = variable_get('mollie_payment_default_api_key_live', '');
    if (!empty($apiKey)) {
      $organizationToken = variable_get('mollie_payment_default_access_token', '');
      if (empty($organizationToken)) {
        $value = 'no organization access token';
        $description = t('There is no default organization access token configured. With an organization access token your Mollie onboarding status can be checked.');
      }
      else {

        // Check the onboarding status. The Mollie API client for PHP does not
        // support this at this moment so we need to do this manually for now.
        $value = $this
          ->getOnboardingStatus();
        switch ($value) {
          case 'needs-data':
            $description = t('Mollie needs more information to enable your account.');
            $url = self::MOLLIE_ACCOUNT_URL;
            break;
          case 'in-review':
            $description = t('Mollie is reviewing your account application.');
            $url = self::MOLLIE_ACCOUNT_URL;
            break;
          case 'completed':
            $description = t('Your default Mollie account has been configured.');
            $severity = REQUIREMENT_OK;
            break;
          default:
            $description = t('The onboarding status of your Mollie account could not be determined.');
            break;
        }
      }
    }
    if ($severity === REQUIREMENT_WARNING) {

      // Add a link to the account configuration form.
      $description .= ' ' . t('Click to <a href="!url">configure your Mollie account</a>.', array(
        '!url' => $url,
      ));
    }
    return $this
      ->formatRequirements('Mollie account', $value, $description, $severity);
  }

  /**
   * Checks if a Mollie payment method has been defined for the Payment module.
   *
   * @return array
   *   An associative array as expected by hook_requirements().
   */
  public function checkMolliePaymentMethod() {
    $value = 'no payment method';
    $description = t('There is no Payment method configured for Mollie.');
    $severity = REQUIREMENT_WARNING;

    // Load payment methods.
    $methods = entity_load('payment_method', FALSE, array(
      'controller_class_name' => MolliePaymentMethodController::class,
    ));
    if (!empty($methods)) {
      $value = 'ok';
      $description = t('There is at least one Mollie payment method configured.');
      $severity = REQUIREMENT_OK;
    }
    if ($severity === REQUIREMENT_WARNING) {

      // Add a link to the form to add a Mollie payment method.
      $description .= ' ' . t('Click to <a href="!url">add a Mollie payment method</a>.', [
        '!url' => url('admin/config/services/payment/method/add/' . MolliePaymentMethodController::class, [
          'query' => [
            'destination' => current_path(),
          ],
        ]),
      ]);
    }
    return $this
      ->formatRequirements('Mollie payment method', $value, $description, $severity);
  }

  /**
   * Installs the Mollie API client for PHP.
   */
  public function installMollieApiClient() {
    try {

      // We cannot use system_retrieve_file() since it utilizes
      // drupal_http_request() which in turn does not properly update the Host
      // header when following redirects. That causes an issue when GitHub
      // redirects to AWS.
      $file_uri = $this
        ->downloadLatestsMollieApiClient();

      // Extract the archive to the libraries directory.
      $directory = 'sites/all/libraries/' . self::LIBRARY_NAME;
      if (module_exists('update')) {
        update_manager_archive_extract(drupal_realpath($file_uri), $directory);
      }
      else {
        $this
          ->extractArchive(drupal_realpath($file_uri), $directory);
      }

      // Clear the libraries cache.
      libraries_cache_clear();
      drupal_set_message(t('The Mollie API client for PHP has been installed.'));
    } catch (\Exception $e) {
      watchdog_exception('mollie_payment', $e);
      drupal_set_message(t('The Mollie API client for PHP could not be installed. See the logs for details.'));
    }
  }

  /**
   * Returns formatted requirements info to be used with hook_requirements().
   *
   * @param $title
   *   The name of the requirement.
   * @param $description
   *   The description of the requirement/status.
   * @param $severity
   *   The requirement's result/severity level as expected by
   *   hook_requirements().
   *
   * @return array
   *   An associative array as expected by hook_requirements().
   *
   * @see hook_requirements()
   */
  protected function formatRequirements($title, $value, $description, $severity) {

    // Add an additional warning to the description if the requirement is
    // not met.
    if (in_array($severity, array(
      REQUIREMENT_WARNING,
      REQUIREMENT_ERROR,
    ))) {
      $description .= ' This needs to solved before payments can be received using Mollie.';
    }
    return array(
      'title' => $title,
      'value' => $value,
      'description' => $description,
      'severity' => $severity,
    );
  }

  /**
   * Downloads the latest version of the client.
   *
   * @return string|bool
   *   The path of the download or false if the client could not be downloaded.
   *
   * @throws \Exception
   */
  protected function downloadLatestsMollieApiClient() {
    $url = $this
      ->getLatestsMollieApiClientUrl();

    // Fetch data from the URL.
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
    $response = curl_exec($curl);
    $info = curl_getinfo($curl);
    curl_close($curl);
    if ($info['http_code'] == 200 && $response) {

      // Write the data to a temporary file.
      $temp_name = drupal_tempnam('temporary://', 'file') . '.zip';
      if (file_put_contents($temp_name, $response) !== FALSE) {
        return $temp_name;
      }
    }
    else {
      throw new \Exception(curl_error($curl));
    }
    return FALSE;
  }

  /**
   * Returns the URL of the zip with the latest version of the client.
   *
   * @return string
   *   The URL of the zip with the latest version of the Mollie API client
   *   for PHP.
   *
   * @throws \Exception
   */
  protected function getLatestsMollieApiClientUrl() {

    // Fetch information about latest release.
    $response = drupal_http_request(self::MOLLIE_API_CLIENT_URL);
    if (isset($response->data)) {
      $release = drupal_json_decode($response->data);

      // Return the URL of the zip.
      if (isset($release['assets']) && !empty($release['assets'])) {
        foreach ($release['assets'] as $asset) {
          if ($asset['content_type'] == 'application/zip') {
            return $asset['browser_download_url'];
          }
        }
      }
    }
    throw new \Exception('The Mollie API client for PHP could not be found on GitHub.');
  }
  protected function getOnboardingStatus() {
    $status = 'unknown';
    $organizationToken = variable_get('mollie_payment_default_access_token', '');
    if (!empty($organizationToken)) {
      $options = array(
        'headers' => array(
          'Authorization' => 'Bearer ' . $organizationToken,
        ),
      );
      $response = drupal_http_request('https://api.mollie.com/v2/onboarding/me', $options);
      if ($response->code == 200) {
        $data = json_decode($response->data);
        return isset($data->status) ? $data->status : $status;
      }
    }
    return $status;
  }

  /**
   * Unpacks a downloaded archive file.
   *
   * We duplicate update_manager_archive_extract() since we do not want this
   * module to depend on the Update manager module.
   *
   * @param $file
   *   The filename of the archive you wish to extract.
   * @param $directory
   *   The directory you wish to extract the archive into.
   *
   * @return \ArchiverInterface
   *  The Archiver object used to extract the archive.
   *
   * @throws \Exception
   */
  protected function extractArchive($file, $directory) {
    $archiver = archiver_get_archiver($file);
    if (!$archiver) {
      throw new \Exception(t('Cannot extract %file, not a valid archive.', array(
        '%file' => $file,
      )));
    }

    // Remove the directory if it exists, otherwise it might contain a mixture of
    // old files mixed with the new files (e.g. in cases where files were removed
    // from a later release).
    $files = $archiver
      ->listContents();

    // Unfortunately, we can only use the directory name to determine the project
    // name. Some archivers list the first file as the directory (i.e., MODULE/)
    // and others list an actual file (i.e., MODULE/README.TXT).
    $project = strtok($files[0], '/\\');
    $extract_location = $directory . '/' . $project;
    if (file_exists($extract_location)) {
      file_unmanaged_delete_recursive($extract_location);
    }
    $archiver
      ->extract($directory);
    return $archiver;
  }

}

Classes

Namesort descending Description
MolliePaymentInstaller Class MolliePaymentInstaller.