Skip to content
Snippets Groups Projects
Commit 1c292153 authored by Ivica Puljic's avatar Ivica Puljic
Browse files

Issue #3107100 by pivica, primsi: Move all related generator code to bs_lib from bs_base

parent cf12fa39
Branches
Tags
1 merge request!1Issue #3107100 by pivica, primsi: Move all related generator code to bs_lib from bs_base
services:
bs_lib.svg_tools:
class: Drupal\bs_lib\SvgTools
bs_lib.theme_tools:
class: Drupal\bs_lib\ThemeTools
This diff is collapsed.
<?php
namespace Drupal\bs_lib;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\DrupalKernel;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Extension\Discovery\RecursiveExtensionFilterIterator;
use Drupal\Core\Site\Settings;
use Exception;
use stdClass;
use Symfony\Component\HttpFoundation\Request;
/**
* Usefull functions for theme inspection.
*/
class ThemeTools {
/**
* Finds all the base themes for the specified theme.
*
* @param array $themes
* An array of available themes.
* @param string $theme
* The name of the theme whose base we are looking for.
*
* @return array
* Returns an array of all the theme's ancestors including specified theme.
*/
public function drupalGetBaseThemes(array $themes, string $theme): array {
$base_themes = [$theme => $themes[$theme]->info['name']];
if (!empty($themes[$theme]->info['base theme'])) {
return $this->drupalGetBaseThemes($themes, $themes[$theme]->info['base theme']) + $base_themes;
}
return $base_themes;
}
/**
* Returns the first parent theme of passed child theme.
*
* @param string $theme_name
* The name of the child theme whose first parent theme we are looking for.
*
* @return string|NULL
* Returns a theme machine name of first parent theme or NULL if parent does
* not exist.
*/
public function drupalGetParentThemeName($theme_name): ?string {
$themes_info = $this->drupalThemeListInfo();
$parent_themes = $this->drupalGetBaseThemes($themes_info, $theme_name);
end($parent_themes);
if (!prev($parent_themes)) {
return NULL;
}
return key($parent_themes);
}
/**
* Returns the path to a Drupal theme.
*
* @param string $name
* Theme machine name.
*
* @return string
* The path to the requested theme or an empty string if the item is not
* found.
*/
public function drupalGetThemePath($name): string {
$scan = $this->drupalScan('theme');
if (isset($scan[$name])) {
return $scan[$name]->subpath;
}
return '';
}
/**
* Get information's for all themes.
*
* @param bool $reset
* Reset internal cache.
*
* @return array
* Array holding themes information's.
*/
public function drupalThemeListInfo(bool $reset = FALSE): array {
static $themes = [];
if (!$reset && !empty($themes)) {
return $themes;
}
$themes = $this->drupalScan('theme', $reset);
foreach ($themes as $theme_name => $theme) {
$themes[$theme_name]->info = Yaml::decode(file_get_contents($theme->pathname));
}
return $themes;
}
/**
* Discovers available extensions of a given type.
*
* For an explanation of how this work see ExtensionDiscovery::scan().
*
* @param string $type
* The extension type to search for. One of 'profile', 'module', 'theme', or
* 'theme_engine'.
* @param bool $reset
* Reset internal cache.
*
* @return array|null
* An associative array of stdClass objects, keyed by extension name.
*/
public function drupalScan(string $type, bool $reset = FALSE): ?array {
static $processed_files = NULL;
if (!$reset && !is_null($processed_files)) {
return $processed_files;
}
$search_dirs = [
ExtensionDiscovery::ORIGIN_SITES_ALL => 'sites/all',
ExtensionDiscovery::ORIGIN_ROOT => ''
];
if (\Drupal::hasService('kernel')) {
$search_dirs[ExtensionDiscovery::ORIGIN_SITE] = \Drupal::getContainer()->getParameter('site.path');
}
else {
$search_dirs[ExtensionDiscovery::ORIGIN_SITE] = DrupalKernel::findSitePath(Request::createFromGlobals());
}
$files = [];
foreach ($search_dirs as $dir) {
$scan_res = $this->drupalScanDirectory($dir);
// Only return extensions of the requested type.
if (isset($scan_res[$type])) {
$files += $scan_res[$type];
}
}
// Duplicate files found in later search directories take precedence over
// earlier ones; they replace the extension in the existing $files array.
$processed_files = [];
foreach ($files as $file) {
$processed_files[basename($file->pathname, '.info.yml')] = $file;
}
return $processed_files;
}
/**
* Recursively scans a base directory for the extensions it contains.
*
* For an explanation of how this work @see
* ExtensionDiscovery::scanDirectory().
*
* @param string $dir
* A relative base directory path to scan, without trailing slash.
*
* @return array
* An associative array of stdClass objects, keyed by extension name.
*/
public function drupalScanDirectory(string $dir): array {
$files = [];
$dir_prefix = ($dir == '' ? '' : "$dir/");
$absolute_dir = ($dir == '' ? DRUPAL_ROOT : DRUPAL_ROOT . "/$dir");
if (!is_dir($absolute_dir)) {
return $files;
}
$flags = \FilesystemIterator::UNIX_PATHS;
$flags |= \FilesystemIterator::SKIP_DOTS;
$flags |= \FilesystemIterator::FOLLOW_SYMLINKS;
$flags |= \FilesystemIterator::CURRENT_AS_SELF;
$directory_iterator = new \RecursiveDirectoryIterator($absolute_dir, $flags);
$ignore_directories = Settings::get('file_scan_ignore_directories', []);
$filter = new RecursiveExtensionFilterIterator($directory_iterator, $ignore_directories);
$iterator = new \RecursiveIteratorIterator($filter,
\RecursiveIteratorIterator::LEAVES_ONLY,
// Suppress filesystem errors in case a directory cannot be accessed.
\RecursiveIteratorIterator::CATCH_GET_CHILD
);
foreach ($iterator as $key => $fileinfo) {
// All extension names in Drupal have to be valid PHP function names due
// to the module hook architecture.
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $fileinfo->getBasename('.info.yml'))) {
continue;
}
// Determine extension type from info file.
$type = FALSE;
/** @var \SplFileObject $file */
$file = $fileinfo->openFile('r');
while (!$type && !$file->eof()) {
preg_match('@^type:\s*(\'|")?(\w+)\1?\s*$@', $file->fgets(), $matches);
if (isset($matches[2])) {
$type = $matches[2];
}
}
if (empty($type)) {
continue;
}
$name = $fileinfo->getBasename('.info.yml');
$pathname = $dir_prefix . $fileinfo->getSubPathname();
// Determine whether the extension has a main extension file.
// For theme engines, the file extension is .engine.
if ($type == 'theme_engine') {
$filename = $name . '.engine';
}
// For profiles/modules/themes, it is the extension type.
else {
$filename = $name . '.' . $type;
}
if (!file_exists(DRUPAL_ROOT . '/' . dirname($pathname) . '/' . $filename)) {
$filename = NULL;
}
$extension = new stdClass();
$extension->type = $type;
$extension->pathname = $pathname;
$extension->filename = $filename;
// Add dir to subpath, so we can work with multisites also.
$extension->subpath = (!empty($dir) ? $dir . '/' : '') . $fileinfo->getSubPath();
// Extension parent folder path.
$extension->parentPath = substr($fileinfo->getPath(), 0, -(strlen($name) + 1));
$extension->origin = $dir;
$files[$type][$key] = $extension;
}
return $files;
}
/**
* Regular expression search and replace in the text.
*
* @param string $text
* Text to search and replace.
* @param array $regexps
* Array of regexps searches with it replace values.
* @param string $modifiers
* PHP regular expression modifiers.
* @param string $delimiter
* PHP regular expression delimiter.
*
* @return string
* Replaced text.
*/
public function regexp(string $text, array $regexps, string $modifiers = 'm', string $delimiter = '%'): string {
$new_content = $text;
foreach ($regexps as $pattern => $value) {
if ($replaced = preg_replace($this->getRegexp($pattern, $modifiers, $delimiter), $value, $new_content)) {
$new_content = $replaced;
}
}
return $new_content;
}
/**
* Regular expression search and replace in the file.
*
* @param string $file_name
* File path.
* @param array $regexps
* Array of regexps searches with it replace values.
*
* @return bool
* TRUE on success, FALSE if file can not be open or saved.
*/
public function regexpFile(string $file_name, array $regexps): bool {
$file_contents = file_get_contents($file_name);
if ($file_contents === FALSE) {
return FALSE;
}
return file_put_contents($file_name, $this->regexp($file_contents, $regexps));
}
/**
* Check does regular expression result exist in the file.
*
* @param string $file_name
* File path.
* @param string $pattern
* Regular expression pattern for search.
*
* @return bool
* TRUE if it exists, FALSE other way.
*
* @throws Exception
*/
public function regexpExist(string $file_name, string $pattern): bool {
$file_contents = file_get_contents($file_name);
if ($file_contents === FALSE) {
throw new Exception("Can not open file $file_name.");
}
$matches = [];
return preg_match($this->getRegexp($pattern), $file_contents, $matches) === 1;
}
/**
* Wraps a regexp pattern.
*
* @param string $pattern
* Regexp pattern.
* @param string $modifiers
* PHP regular expression modifiers.
* @param string $delimiter
* PHP regular expression delimiter.
*
* @return string
* Wrapped regexp pattern.
*/
protected function getRegexp(string $pattern, string $modifiers = 'm', string $delimiter = '%'): string {
return $delimiter . $pattern . $delimiter . $modifiers;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment