next_for_drupal_pantheon-1.0.x-dev/src/PantheonNextInstaller.php

src/PantheonNextInstaller.php
<?php

namespace Drupal\next_for_drupal_pantheon;

use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Password\DefaultPasswordGenerator;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\simple_oauth\Service\KeyGeneratorService;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;

/**
 * Next.js installer.
 *
 * @ingroup next_for_drupal_pantheon
 */
class PantheonNextInstaller implements PantheonNextInstallerInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $configFactory;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $defaultPasswordGenerator;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $keyGeneratorService;

  /**
   * The file system service.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * The uuid service.
   *
   * @var \Drupal\Component\Uuid\UuidInterface
   */
  protected UuidInterface $uuid;

  /**
   * Constructs the NextInstaller service.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Gets config data.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   Used to obtain data from various entity types.
   * @param \Drupal\Core\Password\DefaultPasswordGenerator $password_generator
   *   Calls the core password generator in order to create secret keys.
   * @param \Drupal\simple_oauth\Service\KeyGeneratorService $key_generator_service
   *   Allows us to programmatically generate public and private oauth keys.
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file system service.
   * @param \Drupal\Component\Uuid\UuidInterface $uuid
   *   The Uuid service.
   */
  public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, DefaultPasswordGenerator $password_generator, KeyGeneratorService $key_generator_service, FileSystemInterface $file_system, UuidInterface $uuid) {
    $this->configFactory = $config_factory;
    $this->entityTypeManager = $entity_type_manager;
    $this->defaultPasswordGenerator = $password_generator;
    $this->keyGeneratorService = $key_generator_service;
    $this->fileSystem = $file_system;
    $this->uuid = $uuid;
  }

  /**
   * {@inheritdoc}
   */
  public function run() {
    $this->createPathPatterns();
    $user = $this->createUserAndRole();
    $this->createOauthKeys();
    $this->createSiteAndConsumer($user, 'Next.js Site', 'http://localhost:3000/api/preview/', 'http://localhost:3000');
  }

  /**
   * Configure default content type path aliases.
   */
  public function createPathPatterns() {
    $patterns = [
      'article' => [
        'label' => 'Article',
        'pattern' => '/articles/[node:title]',
      ],
      'recipe' => [
        'label' => 'Recipe',
        'pattern' => '/recipes/[node:title]',
      ],
      'page' => [
        'label' => 'Page',
        'pattern' => '/[node:title]',
      ],
    ];

    $storage = $this->entityTypeManager->getStorage('pathauto_pattern');
    foreach ($patterns as $bundle => $params) {
      // Check if the entity type exists.
      if ($this->entityTypeManager->getStorage('node_type')->load($bundle)) {
        // Checking if patterns exists
        $exists = $storage->getQuery()
          ->condition('selection_criteria.*.id', 'entity_bundle:node')
          ->condition('selection_criteria.*.bundles.' . $bundle, $bundle)
          ->accessCheck(FALSE)
          ->execute();
        if (empty($exists)) {
          $uuid = \Drupal::service('uuid')->generate();
          $pattern = $storage->create([
            'id' => $bundle,
            'label' => $params['label'],
            'type' => 'canonical_entities:node',
            'pattern' => $params['pattern'],
            'selection_criteria' => [
              $uuid => [
                'uuid' => $uuid,
                'id' => 'entity_bundle:node',
                'negate' => FALSE,
                'context_mapping' => [
                  'node' => 'node',
                ],
                'bundles' => [
                  $bundle => $bundle,
                ],
              ],
            ],
          ]);
          $pattern->save();
        }
      }
    }
  }

  /**
   * Configure default content type path aliases.
   */
  public function createNextSite($label = 'Next.js', $preview_url = '/api/preview', $base_url = '') {
    $site_id = $this->getMachineName($label);
    $site_storage = $this->entityTypeManager->getStorage('next_site');
    if (!$next_site = $site_storage->load($site_id)) {
      $next_site = $site_storage->create([
        'id' => $site_id,
        'label' => $label,
        'base_url' => $base_url,
        'preview_url' => $preview_url,
        'preview_secret' => $this->defaultPasswordGenerator->generate(21),
      ]);
      $next_site->save();
    }

    $this->setSiteResolver();
    return $next_site;
  }

  /**
   * Configure default content type path aliases.
   */
  public function createUserAndRole() {
    $role_id = 'next_js';
    $role_storage = $this->entityTypeManager->getStorage('user_role');

    // Create the Next.js role.
    if (!$role = $role_storage->load($role_id)) {
      /** @var \Drupal\user\RoleInterface $role */
      $role = $role_storage->create([
        'id' => $role_id,
        'label' => 'Next.js',
      ]);

      $role->grantPermission('bypass node access');
      $role->grantPermission('issue subrequests');
      $role->grantPermission('access user profiles');
      $role->save();
    }

    // Create the Next.js user.
    // TODO: Make this configurable.
    $email = $this->uuid->generate() . "@" . $this->uuid->generate() . ".com";
    $username = 'Next.js';
    $user_storage = $this->entityTypeManager->getStorage('user');
    $users = $user_storage->loadByProperties(['name' => $username]);
    if ($user = reset($users)) {
      return $user;
    }
    else {
      /** @var \Drupal\user\UserInterface $user */
      $user = $user_storage->create([]);
      $user->setPassword($this->defaultPasswordGenerator->generate(21));
      $user->setEmail($email);
      $user->setUsername($username);
      $user->set('langcode', 'en');
      $user->set('init', $email);
      $user->set('preferred_langcode', 'en');

      // As of Next 1.3, we need to assign all roles for scopes.
      foreach ($this->getUserRoles() as $role_id) {
        $user->addRole($role_id);
      }
      $user->enforceIsNew();
      $user->activate();
      $user->save();
      return $user;
    }
  }

  /**
   * Generate SimpleOauth keys.
   */
  public function createOauthKeys() {
    $oauth = $this->configFactory->getEditable('simple_oauth.settings');
    if (empty($oauth->get('public_key')) && empty($oauth->get('private_key'))) {
      $path = 'public://oauth-keys';
      // Check if the private file stream wrapper is ready to use.
      if (\Drupal::service('stream_wrapper_manager')
        ->isValidScheme('private')) {
        $path = 'private://oauth-keys';
      }
      $this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
      $realpath = $this->fileSystem->realpath($path);

      $this->keyGeneratorService->generateKeys($realpath);
      $oauth->set('public_key', "$realpath/public.key")
        ->set('private_key', "$realpath/private.key")
        ->save();
    }
  }

  /**
   * Create a consumer and set scopes.
   */
  public function createClientScopes($user, $label = 'Next.js') {
    $consumer_storage = $this->entityTypeManager->getStorage('consumer');
    $consumer_entities = $consumer_storage->loadByProperties(['label' => $label]);
    $all_consumer_entities = $consumer_storage->loadMultiple();
    if (!$consumer = reset($consumer_entities)) {
      $consumer = $consumer_storage->create([]);
      $consumer->set('label', $label . ' Consumer');
      $consumer->set('secret', $this->defaultPasswordGenerator->generate(21));
      $consumer->set('is_default', empty($all_consumer_entities) ?? TRUE);
      $consumer->set('redirect', '');
      $consumer->set('roles', 'next_js');
      $consumer->set('user_id', $user->id());
      $consumer->set('client_id', $user->uuid());
      $consumer->save();
    }
    return $consumer;
  }

  /**
   * Create new Pantheon Next.js site entity.
   */
  public function createSiteAndConsumer($user, $label = 'Next.js', $preview_url = 'http://localhost:3000/api/preview', $base_url = 'http://localhost:3000') {
    $label = preg_replace("#[[:punct:]]#", "", $label);
    $consumer = $this->createClientScopes($user, $label);
    $next_site = $this->createNextSite($label, $preview_url, $base_url);
    $this->setSiteResolver();
    $next_for_drupal_pantheon = $this->entityTypeManager->getStorage('next_for_drupal_pantheon')
      ->create([
        'next_site' => $next_site->id(),
        'consumer' => $consumer->id(),
      ]);
    $next_for_drupal_pantheon->save();
    return $next_for_drupal_pantheon;
  }

  /**
   * Create NextEntityTypeConfig entities for content types.
   */
  protected function setSiteResolver() {
    $sites = [];
    $site_storage = $this->entityTypeManager->getStorage('next_site');
    $site_entities = $site_storage->loadMultiple();
    foreach ($site_entities as $site) {
      $sites[$site->id()] = $site->id();
    }

    if ($types = $this->entityTypeManager->getStorage('node_type')
      ->loadMultiple()) {
      foreach ($types as $type) {
        $next_entity_type = $this->entityTypeManager->getStorage('next_entity_type_config');
        if ($existing = $next_entity_type->load("node.{$type->id()}")) {
          $existing->setConfiguration(['sites' => $sites]);
          $existing->save();
        }
        else {
          $next_entity_type->create([
            'id' => "node.{$type->id()}",
            'site_resolver' => 'site_selector',
            'configuration' => [
              'sites' => $sites,
            ],
          ])->save();
        }
      }
    }
  }

  /**
   * Generates a machine name from a string.
   */
  protected function getMachineName($string) {
    $transliterated = \Drupal::transliteration()
      ->transliterate($string, LanguageInterface::LANGCODE_DEFAULT, '_');
    $transliterated = mb_strtolower($transliterated);
    $transliterated = preg_replace('@[^a-z0-9_.]+@', '_', $transliterated);
    return $transliterated;
  }

  /**
   * Returns an array of roles IDs available on the site.
   *
   * @return array
   *   An array of role ids.
   */
  protected function getUserRoles() {
    return $this->entityTypeManager->getStorage('user_role')
      ->getQuery()
      ->condition('id', [
        RoleInterface::AUTHENTICATED_ID,
        Role::ANONYMOUS_ID,
      ], 'NOT IN')
      ->execute();
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc