Esempio n. 1
0
  /**
   * Generate a sub-theme.
   *
   * Need to validate some of this stuff and write proper error handling for when things
   * go wrong, rather than just saying hooray, it worked, when no, it did not...
   */
  public function generateTheme($values) {

    $fileOperations      = new FileOperations();
    $directoryOperations = new DirectoryOperations();

    // Prepare form values and set them into variables
    $machine_name    = $values['generate']['generate_machine_name'];
    $friendly_name   = SafeMarkup::checkPlain($values['generate']['generate_friendly_name']);
    $subtheme_type   = $values['generate']['generate_type'];
    $skin_base_theme = $values['generate']['generate_skin_base'] ?: 0;
    $clone_source    = $values['generate']['generate_clone_source'] ?: '';

    $templates           = $values['generate']['options']['generate_templates'];
    $uikit               = $values['generate']['options']['generate_uikit'];
    $color               = $values['generate']['options']['generate_color'];
    //$dottheme_file       = $values['generate']['options']['generate_themefile'];
    $theme_settings_file = $values['generate']['options']['generate_themesettingsfile'];
    $description         = preg_replace('/[^A-Za-z0-9. ]/', '', $values['generate']['options']['generate_description']);
    $version             = $values['generate']['options']['generate_version'];

    // Generic description if the desc field is not set
    $generic_decription = 'Sub theme of AT Core';

    // Path to themes
    $path = drupal_get_path('theme', 'at_core');
    $at_generator_path = drupal_get_path('theme', 'at_generator');

    // Path to where we will save the cloned theme
    // This could be configurable?
    //$target = $path . '/../../' . $machine_name;
    $at_core_path_parts = explode("/", $path);
    if (in_array('contrib', $at_core_path_parts)) {
      $target_path = array('themes', 'custom');
    }
    else {
      $target_path = array('themes');
    }
    $target_dir = $directoryOperations->directoryPrepare($target_path);
    $target = "$target_dir/$machine_name";

    // Array of UIKit tools
    $uikit_tools = array(
      'package.json',
      '.csslintrc',
      'Gruntfile.js',
      'Gemfile',
      'Gemfile.lock',
    );

    // Standard and Minimal variables
    if ($subtheme_type === 'standard') {
      $source_theme = 'THEMENAME';
      $source = $at_generator_path . '/components/starterkit';
    }

    // Clone variables
    if ($subtheme_type === 'clone') {
      $source_theme = $clone_source;
      $source = drupal_get_path('theme', $source_theme);
    }

    // Skin variables
    if ($subtheme_type === 'skin') {
      $source_theme = $skin_base_theme;
      $source = drupal_get_path('theme', $source_theme);
    }

    // All themes have configuration
    $configuration_files = $directoryOperations->directoryScan("$source/config/install");

    // Files to strip replace strings
    $info_file = "$target/$machine_name.info.yml";
    $library_file = "$target/$machine_name.libraries.yml";
    $shortcodes_file = "$target/$machine_name.shortcodes.yml";

    // Begin generation
    //------------------------------------------------------------------------------------------------

    // Recursively copy the source theme
    if (is_dir($source)) {
      $directoryOperations->directoryRecursiveCopy($source, $target);
    }

    // Genearated CSS files
    $generated_css = $directoryOperations->directoryScan("$source/styles/css/generated");
    foreach ($generated_css as $old_css_file) {
      $new_css_file = str_replace($source_theme, $machine_name, $old_css_file);
      $fileOperations->fileRename("$target/styles/css/generated/$old_css_file", "$target/styles/css/generated/$new_css_file");
    }

    // UIKit and Color
    if ($subtheme_type === 'standard') {

      // UIKit
      if ($uikit === 0) {
        $directoryOperations->directoryRemove("$target/styles/uikit");
        // remove files like GEM, Gruntfile.js etc
        foreach ($uikit_tools as $tool) {
          unlink("$target/$tool");
        }
        // remove all the map files from the css dir "$target/styles/uikit"
        array_map('unlink', glob("$target/styles/css/components/*.map"));
      }

      // Color
      if ($color === 0) {
        $directoryOperations->directoryRemove("$target/color");
        //$directoryOperations->directoryRemove("$target/styles/css/colors.css");

        // If UIKit and not color
        //if ($uikit === 1) {
          //$directoryOperations->directoryRemove("$target/styles/uikit/colors.scss");
          //$directoryOperations->directoryRemove("$target/styles/uikit/components/_colors.scss");
        //}
      }
    }

    // UIKit skins
    if ($subtheme_type === 'skin') {
      $directoryOperations->directoryRemove("$target/styles/uikit");
    }

    // Templates
    if ($subtheme_type === 'standard') {
      $fileOperations->fileStrReplace("$target/templates/page/page.html.twig", 'THEMENAME', $machine_name);
      if ($templates === 1) {
        $directoryOperations->directoryRecursiveCopy("$path/templates", "$target/templates");
      }
    }
    if ($subtheme_type === 'skin') {
      $directoryOperations->directoryRemove("$target/templates");
    }

    // .theme
    if ($subtheme_type === 'standard') {
      $fileOperations->fileRename("$target/$source_theme.theme", "$target/$machine_name.theme");
      $fileOperations->fileStrReplace("$target/$machine_name.theme", 'HOOK', $machine_name);
    }
    if ($subtheme_type === 'clone') {
      $fileOperations->fileRename("$target/$source_theme.theme", "$target/$machine_name.theme");
      $fileOperations->fileStrReplace("$target/$machine_name.theme", $source_theme, $machine_name);
    }
    if ($subtheme_type === 'skin') {
      $fileOperations->fileRename("$target/$source_theme.theme", "$target/$machine_name.theme");
      $skin_theme = file_get_contents("$at_generator_path/components/starterkit_skin/SKIN.theme");
      $fileOperations->fileReplace($skin_theme, "$target/$machine_name.theme");
      $fileOperations->fileStrReplace("$target/$machine_name.theme", 'HOOK', $machine_name);
    }

    // libraries
    $fileOperations->fileRename("$target/$source_theme.libraries.yml", $library_file);

    //if ($subtheme_type === 'standard') {
      //if ($color === 0) {
      //  $fileOperations->fileStrReplace($library_file, 'styles/css/colors.css: {}', '');
      //}
    //}

    if ($subtheme_type === 'skin') {
      $skin_libraries = file_get_contents("$at_generator_path/components/starterkit_skin/SKIN.libraries.yml");
      $fileOperations->fileReplace($skin_libraries, "$target/$library_file");
      $directoryOperations->directoryRemove("$target/styles/css/components");
      $directoryOperations->directoryRecursiveCopy("$at_generator_path/components", "$target/styles/css");

      //$fileOperations->fileStrReplace($library_file, 'styles/css/styles.css: {}', "styles/css/$machine_name-styles.css: {}");
      //$directoryOperations->directoryRemove("$target/styles/css/styles.css");
      //$fileOperations->fileRename("$target/styles/css/styles.css", "$target/styles/css/$machine_name-styles.css");
      //$skin_styles = '/* Styles for ' . $machine_name . ' */';
      //$fileOperations->fileReplace($skin_styles, "$target/styles/css/$machine_name-styles.css");
    }

    // theme-settings.php
    if ($subtheme_type === 'standard') {
      if ($theme_settings_file === 1) {
        $fileOperations->fileStrReplace("$target/theme-settings.php", 'HOOK', $machine_name);
      }
      else {
        $directoryOperations->directoryRemove("$target/theme-settings.php");
      }
    }
    if ($subtheme_type === 'clone') {
      $fileOperations->fileStrReplace("$target/theme-settings.php", $source_theme, $machine_name);
    }
    if ($subtheme_type === 'skin') {
      $directoryOperations->directoryRemove("$target/theme-settings.php");
    }

    // Config
    foreach ($configuration_files as $old_config_file) {
      $new_config_file = str_replace($source_theme, $machine_name, $old_config_file);
      $fileOperations->fileRename("$target/config/install/$old_config_file", "$target/config/install/$new_config_file");
      $fileOperations->fileStrReplace("$target/config/install/$new_config_file", 'TARGET', $target);
      $fileOperations->fileStrReplace("$target/config/install/$new_config_file", $source_theme, $machine_name);
    }
    // Skin and clone need their source themes configuration
    if ($subtheme_type === 'skin' || $subtheme_type === 'clone') {
      $source_config = \Drupal::config($source_theme . '.settings')->get();
      // Empty if the source theme has never been installed, in which case it should be safe to assume
      // there is no new configuration worth saving.
      if (!empty($source_config)) {
        $old_config = "$target/config/install/$machine_name.settings.yml";
        $new_config = Yaml::encode($source_config);
        $find_generated_files = "themes/$source_theme/styles/css/generated";
        $replace_generated_files = "themes/$machine_name/styles/css/generated";
        $new_config = str_replace($find_generated_files, $replace_generated_files, $new_config);
        $fileOperations->fileReplace($new_config, $old_config);
      }
    }

    // Info
    $fileOperations->fileRename("$target/$source_theme.info.yml", $info_file);

    // Shortcodes
    $fileOperations->fileRename("$target/$source_theme.shortcodes.yml", $shortcodes_file);

    // Parse, rebuild and save the themes info.yml file.
    $parser = new Parser();
    $theme_info_data = $parser->parse(file_get_contents($info_file));

    // Name and theme type
    $theme_info_data['name'] = "$friendly_name";
    $theme_info_data['type'] = "theme";

    // Base theme
    if ($subtheme_type === 'skin') {
      $theme_info_data['base theme'] = $source_theme;
    }

    // Description
    $base_theme = $theme_info_data['base theme'];
    if ($subtheme_type === 'clone') {
      $description = $description ?: 'Clone of ' . $source_theme;
    }
    if ($subtheme_type === 'skin') {
      $base_theme = $source_theme;
      $description = $description ?: 'Skin theme';
    }
    $description = $description ?: $generic_decription;
    $theme_info_data['description'] = "$description (base theme: $base_theme)";

    // alt text
    $theme_info_data['alt text'] = "Screenshot for $friendly_name";

    // Version
    $version = $version ?: '8.0.x';
    $theme_info_data['version']     = $version;

    // Regions
    foreach($theme_info_data['regions'] as $region_key => $region_name) {
      $theme_info_data['regions'][$region_key] = "$region_name";
    }

    // Unset hidden
    unset($theme_info_data['hidden']);

    // Unset stylesheets-remove
    //if ($subtheme_type === 'skin') {
    //  unset($theme_info_data['stylesheets-remove']);
    //}

    // Libraries
    $theme_info_data['libraries-override'] = $theme_info_data['libraries-override'];

    // Save the info file
    $rebuilt_info = $fileOperations->fileBuildInfoYml($theme_info_data);
    $fileOperations->fileReplace($rebuilt_info, $info_file);


    // Set messages, however we may need more validation?
    //----------------------------------------------------------------------
    $generated_path = drupal_get_path('theme', $machine_name);

    // system message for Reports.
    $logger_message = t('A new theme <b>@theme_name</b>, with then machine name: <code><b>@machine_name</b></code>, has been generated.', array('@theme_name' => $friendly_name, '@machine_name' => $machine_name));
    \Drupal::logger('at_generator')->notice($logger_message);

    // message for the user
    drupal_set_message(t("<p>A new theme <b>@theme_name</b>, with then machine name: <code><b>@machine_name</b></code>, has been generated.</p><p>You can find your theme here: <code><b>@theme_path</b></code> </p>", array('@theme_name' => $friendly_name, '@machine_name' => $machine_name, '@theme_path' => $target, '@performance_settings' => base_path() . 'admin/config/development/performance')), 'status');


    // Refresh data.
    system_list_reset();
    \Drupal::service('theme_handler')->rebuildThemeData();


    /*
    // Warn about stylesheets in the new skin theme
    if ($subtheme_type === 'at_skin') {
      drupal_set_message(t('Skin themes do not inherit theme <em>settings</em>, this is important for things like Layout and Library settings. After you enable your new theme be sure to check and configure it\'s settings.', array('!theme_path' => $generated_path, '!machine_name' => $machine_name)), 'warning');
    }
   */
  }
Esempio n. 2
0
/**
 * Form submit handler for the theme settings form.
 * @param $form
 * @param $form_state
 */
function at_generator_submit_generator(&$form, &$form_state)
{
    $build_info = $form_state->getBuildInfo();
    $values = $form_state->getValues();
    $theme = $build_info['args'][0];
    // Generate a new theme.
    if (!empty($values['generate']['generate_machine_name']) && $theme == 'at_generator') {
        $fileOperations = new FileOperations();
        $directoryOperations = new DirectoryOperations();
        // Prepare form values and set them into variables.
        $machine_name = $values['generate']['generate_machine_name'];
        $friendly_name = Html::escape($values['generate']['generate_friendly_name']);
        $subtheme_type = $values['generate']['generate_type'];
        //$skin_base_theme     = $values['generate']['generate_skin_base'] ?: 0;
        $clone_source = $values['generate']['generate_clone_source'] ?: '';
        $templates = $values['generate']['options']['generate_templates'];
        $uikit = $values['generate']['options']['generate_uikit'];
        $color = $values['generate']['options']['generate_color'];
        $theme_settings_file = $values['generate']['options']['generate_themesettingsfile'];
        $description = preg_replace('/[^A-Za-z0-9. ]/', '', Html::escape($values['generate']['options']['generate_description']));
        $version = Html::escape($values['generate']['options']['generate_version']);
        // Initialize variables.
        $source = '';
        $source_theme = '';
        // Generated date time for descriptions.
        $datetime = \Drupal::service('date.formatter')->format(REQUEST_TIME, 'custom', 'D jS, M - G:i');
        // Generic description if the desc field is not set.
        $generic_description = 'Sub theme of AT Core';
        // Path to themes
        $path = drupal_get_path('theme', 'at_core');
        $at_generator_path = drupal_get_path('theme', 'at_generator');
        // Path to where we will save the cloned theme.
        // This could be configurable?
        $at_core_path_parts = explode("/", $path);
        if (in_array('contrib', $at_core_path_parts)) {
            $target_path = array('themes', 'custom');
        } else {
            $target_path = array('themes');
        }
        $target_dir = $directoryOperations->directoryPrepare($target_path);
        $target = "{$target_dir}/{$machine_name}";
        if (!is_writable('themes')) {
            drupal_set_message(t('The "themes" directory is not writable. To generate a new theme reset permissions for the "@themespath" directory so it is writable, e.g. chmod themes 0755.', array('@themespath' => base_path() . 'themes')), 'error');
            return;
        }
        // Array of UIKit tools.
        $uikit_tools = array('package.json', '.csslintrc', 'Gruntfile.js', 'Gemfile', 'Gemfile.lock');
        // Standard and Minimal variables.
        if ($subtheme_type === 'standard') {
            $source_theme = 'THEMENAME';
            $source = $at_generator_path . '/components/starterkit';
        }
        // Clone variables.
        if ($subtheme_type === 'clone') {
            $source_theme = $clone_source;
            $source = drupal_get_path('theme', $source_theme);
        }
        // Skin variables.
        //    if ($subtheme_type === 'skin') {
        //      $source_theme = $skin_base_theme;
        //      $source = drupal_get_path('theme', $source_theme);
        //    }
        // All themes have configuration.
        $configuration_files = $directoryOperations->directoryScan("{$source}/config/install");
        // Files to strip replace strings
        $info_file = "{$target}/{$machine_name}.info.yml";
        $library_file = "{$target}/{$machine_name}.libraries.yml";
        $shortcodes_file = "{$target}/{$machine_name}.shortcodes.yml";
        // Begin generation.
        //------------------------------------------------------------------------------------------------
        // Recursively copy the source theme.
        if (is_dir($source)) {
            $directoryOperations->directoryRecursiveCopy($source, $target);
        }
        // Generated CSS files.
        $generated_css = $directoryOperations->directoryScan("{$source}/styles/css/generated");
        foreach ($generated_css as $old_css_file) {
            $new_css_file = str_replace($source_theme, $machine_name, $old_css_file);
            $fileOperations->fileRename("{$target}/styles/css/generated/{$old_css_file}", "{$target}/styles/css/generated/{$new_css_file}");
        }
        // UIKit and Color
        if ($subtheme_type === 'standard') {
            // UIKit
            if ($uikit === 0) {
                $directoryOperations->directoryRemove("{$target}/styles/uikit");
                // remove files like GEM, Gruntfile.js etc
                foreach ($uikit_tools as $tool) {
                    unlink("{$target}/{$tool}");
                }
                // Remove all SASS map files and references.
                array_map('unlink', glob("{$target}/styles/css/components/*.map"));
                $component_css_files = $directoryOperations->directoryScan("{$target}/styles/css/components");
                foreach ($component_css_files as $component_file_key => $component_file) {
                    $map_string = '/*# sourceMappingURL=' . str_replace('.css', '.css.map', $component_file) . ' */';
                    $fileOperations->fileStrReplace("{$target}/styles/css/components/{$component_file}", $map_string, '');
                }
            }
            // Color.
            if ($color === 0) {
                $directoryOperations->directoryRemove("{$target}/color");
            }
        }
        // UIKit skins.
        //if ($subtheme_type === 'skin') {
        //  $directoryOperations->directoryRemove("$target/styles/uikit");
        //}
        // Templates.
        if ($subtheme_type === 'standard') {
            $fileOperations->fileStrReplace("{$target}/templates/generated/page.html.twig", 'THEMENAME', $machine_name);
            if ($templates === 1) {
                $directoryOperations->directoryRecursiveCopy("{$path}/templates", "{$target}/templates");
            }
        }
        if ($subtheme_type === 'clone') {
            $cloned_templates = $directoryOperations->directoryScan("{$target}/templates/generated");
            foreach ($cloned_templates as $cloned_template) {
                $fileOperations->fileStrReplace("{$target}/templates/generated/{$cloned_template}", $source_theme, $machine_name);
            }
        }
        //if ($subtheme_type === 'skin') {
        //  $directoryOperations->directoryRemove("$target/templates");
        //}
        // .theme
        if ($subtheme_type === 'standard') {
            $fileOperations->fileRename("{$target}/{$source_theme}.theme", "{$target}/{$machine_name}.theme");
            $fileOperations->fileStrReplace("{$target}/{$machine_name}.theme", 'HOOK', $machine_name);
        }
        if ($subtheme_type === 'clone') {
            $fileOperations->fileRename("{$target}/{$source_theme}.theme", "{$target}/{$machine_name}.theme");
            $fileOperations->fileStrReplace("{$target}/{$machine_name}.theme", $source_theme, $machine_name);
        }
        //    if ($subtheme_type === 'skin') {
        //      $fileOperations->fileRename("$target/$source_theme.theme", "$target/$machine_name.theme");
        //      $skin_theme = file_get_contents("$at_generator_path/components/starterkit_skin/SKIN.theme");
        //      $fileOperations->fileReplace($skin_theme, "$target/$machine_name.theme");
        //      $fileOperations->fileStrReplace("$target/$machine_name.theme", 'HOOK', $machine_name);
        //    }
        // libraries
        $fileOperations->fileRename("{$target}/{$source_theme}.libraries.yml", $library_file);
        //    if ($subtheme_type === 'skin') {
        //      $skin_libraries = file_get_contents("$at_generator_path/components/starterkit_skin/SKIN.libraries.yml");
        //      $fileOperations->fileReplace($skin_libraries, "$target/$library_file");
        //      $directoryOperations->directoryRemove("$target/styles/css/components");
        //      $directoryOperations->directoryRecursiveCopy("$at_generator_path/components", "$target/styles/css");
        //    }
        // theme-settings.php
        if ($subtheme_type === 'standard') {
            if ($theme_settings_file === 1) {
                $fileOperations->fileStrReplace("{$target}/theme-settings.php", 'HOOK', $machine_name);
            } else {
                $directoryOperations->directoryRemove("{$target}/theme-settings.php");
            }
        }
        if ($subtheme_type === 'clone') {
            $fileOperations->fileStrReplace("{$target}/theme-settings.php", $source_theme, $machine_name);
        }
        //    if ($subtheme_type === 'skin') {
        //      $directoryOperations->directoryRemove("$target/theme-settings.php");
        //    }
        // Config.
        foreach ($configuration_files as $old_config_file) {
            $new_config_file = str_replace($source_theme, $machine_name, $old_config_file);
            $fileOperations->fileRename("{$target}/config/install/{$old_config_file}", "{$target}/config/install/{$new_config_file}");
            $fileOperations->fileStrReplace("{$target}/config/install/{$new_config_file}", 'TARGET', $target);
            $fileOperations->fileStrReplace("{$target}/config/install/{$new_config_file}", $source_theme, $machine_name);
        }
        // Skin and clone need their source themes configuration.
        //if ($subtheme_type === 'skin' || $subtheme_type === 'clone') {
        if ($subtheme_type === 'clone') {
            $source_config = \Drupal::config($source_theme . '.settings')->get();
            // Empty if the source theme has never been installed, in which case it
            // should be safe to assume there is no new configuration worth saving.
            if (!empty($source_config)) {
                $old_config = "{$target}/config/install/{$machine_name}.settings.yml";
                $new_config = Yaml::encode($source_config);
                $find_generated_files = "themes/{$source_theme}/styles/css/generated";
                $replace_generated_files = "themes/{$machine_name}/styles/css/generated";
                $new_config = str_replace($find_generated_files, $replace_generated_files, $new_config);
                $fileOperations->fileReplace($new_config, $old_config);
                $fileOperations->fileStrReplace("{$target}/config/install/{$new_config_file}", $source_theme, $machine_name);
            }
        }
        // Info.
        $fileOperations->fileRename("{$target}/{$source_theme}.info.yml", $info_file);
        // Shortcodes.
        $fileOperations->fileRename("{$target}/{$source_theme}.shortcodes.yml", $shortcodes_file);
        // Parse, rebuild and save the themes info.yml file.
        $parser = new Parser();
        $theme_info_data = $parser->parse(file_get_contents($info_file));
        // Name and theme type.
        $theme_info_data['name'] = "{$friendly_name}";
        $theme_info_data['type'] = "theme";
        // Base theme.
        //    if ($subtheme_type === 'skin') {
        //      $theme_info_data['base theme'] = $source_theme;
        //    }
        // Description.
        $base_theme = $theme_info_data['base theme'];
        if ($subtheme_type === 'clone') {
            $description = $description ?: 'Clone of ' . $source_theme;
        }
        //    if ($subtheme_type === 'skin') {
        //      $base_theme = $source_theme;
        //      $description = $description ?: 'Skin theme';
        //    }
        $description = $description ?: $generic_description;
        $theme_info_data['description'] = "{$description} (base theme: {$base_theme}).<br /> Generated: {$datetime}";
        // alt text.
        $theme_info_data['alt text'] = "Screenshot for {$friendly_name}";
        // Version.
        $theme_info_data['version'] = $version ? str_replace(' ', '-', trim($version)) : '8.0.x';
        // Regions.
        foreach ($theme_info_data['regions'] as $region_key => $region_name) {
            $theme_info_data['regions'][$region_key] = "{$region_name}";
        }
        // Unset stuff we don't want or need.
        unset($theme_info_data['hidden']);
        unset($theme_info_data['project']);
        unset($theme_info_data['datestamp']);
        // Libraries.
        if (isset($theme_info_data['libraries-extend']['quickedit/quickedit'])) {
            $theme_info_data['libraries-extend']['quickedit/quickedit'] = array($machine_name . '/quickedit');
        }
        // Save the info file.
        $rebuilt_info = $fileOperations->fileBuildInfoYml($theme_info_data);
        $fileOperations->fileReplace($rebuilt_info, $info_file);
        // Set messages, however we may need more validation?
        //----------------------------------------------------------------------
        // system message for Reports.
        $logger_message = t('A new theme <b>@theme_name</b>, with then machine name: <code><b>@machine_name</b></code>, has been generated.', array('@theme_name' => $friendly_name, '@machine_name' => $machine_name));
        \Drupal::logger('at_generator')->notice($logger_message);
        // Message for the user.
        drupal_set_message(t("<p>A new theme <b>@theme_name</b>, with then machine name: <code><b>@machine_name</b></code>, has been generated.</p><p>You can find your theme here: <code><b>@theme_path</b></code> </p>", array('@theme_name' => $friendly_name, '@machine_name' => $machine_name, '@theme_path' => $target, '@performance_settings' => base_path() . 'admin/config/development/performance')), 'status');
        // Refresh data.
        system_list_reset();
        \Drupal::service('theme_handler')->rebuildThemeData();
    } else {
        drupal_set_message(t('Bummer, something went wrong, please try again.'));
    }
}
Esempio n. 3
0
 /**
  * {@inheritdoc}
  */
 public function saveLayoutSuggestionsMarkup()
 {
     $template_suggestions = array();
     $fileOperations = new FileOperations();
     $directoryOperations = new DirectoryOperations();
     if (!empty($this->form_values['settings_suggestions'])) {
         $template_suggestions = $this->form_values['settings_suggestions'];
     }
     if (!empty($this->form_values['ts_name'])) {
         $template_suggestions['page__' . $this->form_values['ts_name']] = 'page__' . $this->form_values['ts_name'];
     }
     // Don't regenerate templates to be deleted.
     foreach ($this->form_values as $values_key => $values_value) {
         if (substr($values_key, 0, 18) === 'delete_suggestion_') {
             if ($values_value === 1) {
                 $delete_suggestion_keys[] = Unicode::substr($values_key, 18);
             }
         }
     }
     if (!empty($delete_suggestion_keys)) {
         foreach ($delete_suggestion_keys as $template_to_remove) {
             unset($template_suggestions[$template_to_remove]);
         }
     }
     // Template path.
     $template_file = $this->layout_path . '/' . $this->layout_name . '.html.twig';
     // Path to target theme where the template will be saved.
     $path = drupal_get_path('theme', $this->theme_name);
     // Remove if this exists, its now deprecated, this is a BC layer so to speak.
     $directoryOperations->directoryRemove($path . '/templates/page');
     $template_directory = $path . '/templates/generated';
     // Check and create the templates directory if does not exist.
     if (!file_exists($path . '/templates')) {
         \Drupal::service('file_system')->mkdir($path . '/templates');
     }
     if (!file_exists($template_directory)) {
         \Drupal::service('file_system')->mkdir($template_directory);
     }
     // Initialize vars.
     $row_regions = array();
     $templates = array();
     $saved_templates = array();
     // We have to save every template every time, in case a row has been added to the layout, all template MUST update.
     // This could be changed later to only do this IF a row has been added, we're not that flash right now :)
     foreach ($template_suggestions as $suggestion_key => $suggestions_name) {
         $output = array();
         $suggestion_key = Html::escape($suggestion_key);
         // Doc block.
         $doc = array();
         $doc[$suggestion_key][] = '{#';
         $doc[$suggestion_key][] = '/**';
         $doc[$suggestion_key][] = ' * ' . $this->layout_name . ' ' . $suggestion_key . ' template.';
         $doc[$suggestion_key][] = ' * Generated on: ' . date(DATE_RFC822);
         $doc[$suggestion_key][] = ' */';
         $doc[$suggestion_key][] = '#}' . "\n";
         $docblock[$suggestion_key] = implode("\n", $doc[$suggestion_key]);
         // Attach layout.
         $generated_files_path = $this->form_values['settings_generated_files_path'];
         $layout_file = $this->theme_name . '.layout.' . str_replace('_', '-', $suggestion_key) . '.css';
         if (file_exists($generated_files_path . '/' . $layout_file)) {
             $library = $this->theme_name . '/' . $this->theme_name . '.layout.' . $suggestion_key;
         } else {
             $library = $this->theme_name . '/' . $this->theme_name . '.layout.page';
         }
         $attach_layout = "{{ attach_library('{$library}') }}";
         // Get the template file, if not found attempt to generate template
         // code programmatically.
         if (file_exists($template_file)) {
             $template = file_get_contents($template_file);
         } else {
             foreach ($this->layout_config['rows'] as $row => $row_values) {
                 // Row attributes.
                 $attributes[$row]['class'][] = 'l-pr page__row';
                 $attributes[$row]['class'][] = 'pr-' . $row;
                 foreach ($row_values['attributes'] as $attribute_type => $attribute_values) {
                     if (is_array($attribute_values)) {
                         $attributes[$row][$attribute_type][] = implode(' ', $attribute_values);
                     } else {
                         $attributes[$row][$attribute_type][] = $attribute_values;
                     }
                 }
                 ksort($attributes[$row], SORT_STRING);
                 foreach ($attributes[$row] as $attr_type => $attr_array_vales) {
                     $attr_array_vales = array_unique($attr_array_vales);
                     $this_row_attr[$row][$attr_type] = $attr_type . '="' . implode(' ', $attr_array_vales) . '"';
                 }
                 $wrapper_element[$suggestion_key] = 'div';
                 if ($row == 'header' || $row == 'footer') {
                     $wrapper_element[$suggestion_key] = $row;
                 }
                 $output[$suggestion_key][$row]['prefix'] = '  {% if ' . $row . '.has_regions == true %}';
                 $output[$suggestion_key][$row]['wrapper_open'] = '    <' . $wrapper_element[$suggestion_key] . '{{ ' . $row . '.wrapper_attributes }}>';
                 $output[$suggestion_key][$row]['container_open'] = '      <div{{ ' . $row . '.container_attributes }}>';
                 foreach ($row_values['regions'] as $region_name => $region_value) {
                     $row_regions[$suggestion_key][$row][] = '        {{ page.' . $region_name . ' }}';
                 }
                 $output[$suggestion_key][$row]['regions'] = implode("\n", $row_regions[$suggestion_key][$row]);
                 $output[$suggestion_key][$row]['container_close'] = '      </div>';
                 $output[$suggestion_key][$row]['wrapper_close'] = '    </' . $wrapper_element[$suggestion_key] . '>';
                 $output[$suggestion_key][$row]['suffix'] = '  {% endif %}' . "\n";
             }
             $generated[$suggestion_key][] = '<div{{ attributes }}>' . "\n";
             foreach ($output[$suggestion_key] as $row_output) {
                 $generated[$suggestion_key][] = implode("\n", $row_output);
             }
             $generated[$suggestion_key][] = "  {{ attribution }}" . "\n";
             $generated[$suggestion_key][] = '</div>' . "\n";
             $template[$suggestion_key] = implode($generated[$suggestion_key]);
         }
         // Prepend the docblock to the template markup.
         $template_markup[$suggestion_key] = $docblock[$suggestion_key] . $attach_layout . "\n" . $template[$suggestion_key];
         // Set the template file, either it's page or a page suggestion.
         if ($suggestion_key !== 'page') {
             $template_file = str_replace('_', '-', $suggestion_key) . '.html.twig';
         } else {
             $template_file = 'page.html.twig';
         }
         // Set the template path.
         $template_path = $template_directory . '/' . $template_file;
         // Build array of files to be saved.
         $templates[$suggestion_key]['markup'] = $template_markup[$suggestion_key];
         $templates[$suggestion_key]['template_path'] = $template_path;
         $templates[$suggestion_key]['template_name'] = $template_file;
         // Create a backup.
         if ($this->form_values['settings_enable_backups'] == 1) {
             $backup_path = $directoryOperations->directoryPrepare($backup_file_path = array($path, 'backup', 'templates'));
             //Add a date time string to make unique and for easy identification,
             // save as .txt to avoid conflicts.
             $backup_file = $template_file . '.' . date(DATE_ISO8601) . '.txt';
             $file_paths = array('copy_source' => $template_path, 'copy_dest' => $backup_path . '/' . $template_file, 'rename_oldname' => $backup_path . '/' . $template_file, 'rename_newname' => $backup_path . '/' . $backup_file);
             $fileOperations->fileCopyRename($file_paths);
         }
     }
     foreach ($templates as $suggestion => $template_values) {
         if (!file_exists($templates[$suggestion]['template_path'])) {
             $new_template = $templates[$suggestion]['template_name'];
             $new_template_message = t('It looks like you generated a new template: <b>@new_template</b>. Save the layout settings again so they will take effect.', array('@new_template' => $new_template));
         }
         file_unmanaged_save_data($templates[$suggestion]['markup'], $templates[$suggestion]['template_path'], FILE_EXISTS_REPLACE);
         if (file_exists($templates[$suggestion]['template_path'])) {
             $saved_templates[] = $templates[$suggestion]['template_name'];
         }
     }
     if (!empty($saved_templates)) {
         $saved_templates_message_list = array('#theme' => 'item_list', '#items' => $saved_templates);
         drupal_set_message(t('The following <b>templates</b> were generated in: <code>@template_directory</code> @saved_templates', array('@saved_templates' => \Drupal::service('renderer')->renderPlain($saved_templates_message_list), '@template_directory' => $template_directory . '/')), 'status');
     }
     if (isset($new_template_message)) {
         drupal_set_message($new_template_message, 'status');
     }
 }