You are here

apigee_api_catalog.module in Apigee API Catalog 8.2

Same filename and directory in other branches
  1. 8 apigee_api_catalog.module

Copyright 2019 Google Inc.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

File

apigee_api_catalog.module
View source
<?php

/**
 * @file
 * Copyright 2019 Google Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License version 2 as published by the
 * Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
 * License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file
 * Module file for Apigee Edge: API Docs.
 */
use Drupal\apigee_api_catalog\SpecFetcherInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;

/**
 * Implements hook_help().
 */
function apigee_api_catalog_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help for the apigee_api_catalog module.
    case 'help.page.apigee_api_catalog':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Display documentation of your APIs to your developers using OpenAPI documentation.') . '</p>';
      return $output;
    default:
  }
}

/**
 * Implements hook_entity_type_build().
 */
function apigee_api_catalog_entity_type_build(array &$entity_types) {
  if (isset($entity_types['node'])) {

    // Add the reimport form class and link template. The route access check
    // makes sure it does not show up for other node types.
    $entity_types['node']
      ->setFormClass('reimport_spec', '\\Drupal\\apigee_api_catalog\\Entity\\Form\\ApiDocReimportSpecForm');
    $entity_types['node']
      ->setLinkTemplate('reimport-spec-form', '/node/{node}/reimport');
  }
}

/**
 * Implements hook_entity_bundle_field_info_alter().
 */
function apigee_api_catalog_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
  if ($entity_type
    ->id() == 'node' && $bundle == 'apidoc' && !empty($fields['field_apidoc_file_link'])) {
    $fields['field_apidoc_file_link']
      ->addConstraint('ApiDocFileLink', []);
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function apigee_api_catalog_node_presave(EntityInterface $entity) {

  /* @var \Drupal\node\NodeInterface $entity */
  if ($entity
    ->bundle() != 'apidoc') {
    return;
  }

  // Fetch spec file if using URL.
  if ($entity
    ->get('field_apidoc_spec_file_source')->value === SpecFetcherInterface::SPEC_AS_URL) {
    \Drupal::service('apigee_api_catalog.spec_fetcher')
      ->fetchSpec($entity);
  }

  // API docs that use the "file" source will still need their md5 updated.
  if ($entity
    ->get('field_apidoc_spec_file_source')->value === SpecFetcherInterface::SPEC_AS_FILE) {
    $spec_value = $entity
      ->get('field_apidoc_spec')
      ->isEmpty() ? [] : $entity
      ->get('field_apidoc_spec')
      ->getValue()[0];
    if (!empty($spec_value['target_id'])) {

      /* @var \Drupal\file\Entity\File $file */
      $file = \Drupal::entityTypeManager()
        ->getStorage('file')
        ->load($spec_value['target_id']);
      if ($file) {
        $entity
          ->set('field_apidoc_spec_md5', md5_file($file
          ->getFileUri()));
      }
    }
  }
}

/**
 * Implements hook_entity_operation().
 */
function apigee_api_catalog_entity_operation(EntityInterface $entity) {
  $operations = [];
  if ($entity
    ->bundle() == 'apidoc' && $entity
    ->access('update')) {
    if ($entity
      ->hasLinkTemplate('reimport-spec-form')) {
      $operations['reimport_spec'] = [
        'title' => t('Re-import OpenAPI spec'),
        'weight' => 100,
        'url' => $entity
          ->toUrl('reimport-spec-form')
          ->setOption('query', \Drupal::destination()
          ->getAsArray()),
      ];
    }
  }
  return $operations;
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function apigee_api_catalog_node_insert(EntityInterface $entity) {
  apigee_api_catalog_node_update($entity);
}

/**
 * Implements hook_ENTITY_TYPE_update().
 */
function apigee_api_catalog_node_update(EntityInterface $entity) {
  if ($entity
    ->bundle() == 'apidoc') {
    $systemPath = '/node/' . $entity
      ->id();
    $langCode = $entity
      ->language()
      ->getId();
    $exists = \Drupal::service('path_alias.manager')
      ->getAliasByPath($systemPath, $langCode);
    if ($exists == $systemPath) {
      \Drupal::entityTypeManager()
        ->getStorage('path_alias')
        ->create([
        'path' => $systemPath,
        'alias' => '/api/' . $entity
          ->id(),
        'langcode' => $langCode,
      ])
        ->save();
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function apigee_api_catalog_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $node = $form_state
    ->getFormObject()
    ->getEntity();
  if ($node
    ->bundle() != 'apidoc') {
    return;
  }
  $form['field_apidoc_spec']['#states'] = [
    'visible' => [
      ':input[name="field_apidoc_spec_file_source"]' => [
        'value' => SpecFetcherInterface::SPEC_AS_FILE,
      ],
    ],
  ];

  // @todo: #states does not work on managed files.
  // @see: https://www.drupal.org/project/drupal/issues/2847425
  $form['field_apidoc_spec']['widget'][0]['#states'] = [
    'required' => [
      ':input[name="field_apidoc_spec_file_source"]' => [
        'value' => SpecFetcherInterface::SPEC_AS_FILE,
      ],
    ],
  ];
  $form['field_apidoc_file_link']['#states'] = [
    'visible' => [
      [
        ':input[name="field_apidoc_spec_file_source"]' => [
          'value' => SpecFetcherInterface::SPEC_AS_URL,
        ],
      ],
    ],
  ];
  $form['field_apidoc_file_link']['widget'][0]['uri']['#states'] = [
    'required' => [
      [
        ':input[name="field_apidoc_spec_file_source"]' => [
          'value' => SpecFetcherInterface::SPEC_AS_URL,
        ],
      ],
    ],
  ];
  $form['#validate'][] = '_apigee_api_catalog_form_node_form_validate';
}

/**
 * Form validator for the "apidoc" node bundle.
 *
 * @param array $form
 *   The form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The form state.
 */
function _apigee_api_catalog_form_node_form_validate(&$form, FormStateInterface $form_state) {
  $values = $form_state
    ->getValues();
  if (empty($values['field_apidoc_spec_file_source'])) {
    return;
  }

  // Make sure the field_apidoc_spec (file) or field_apidoc_file_link (link)
  // is not empty, according to what was selected as the file source.
  $source = $values['field_apidoc_spec_file_source'][0]['value'] ?: NULL;
  if ($source == SpecFetcherInterface::SPEC_AS_FILE && empty($values['field_apidoc_spec'][0]['fids'][0])) {
    $form_state
      ->setErrorByName('field_apidoc_spec', t('Provide an OpenAPI specification file.'));
  }
  elseif ($source == SpecFetcherInterface::SPEC_AS_URL && empty($values['field_apidoc_file_link'][0]['uri'])) {
    $form_state
      ->setErrorByName('field_apidoc_file_link', t('Provide the URL to an OpenAPI specification file.'));
  }
}