file Theme.php

Namespace

Drupal\bootstrap
  1. <?php
  2. namespace Drupal\bootstrap;
  3. use Drupal\bootstrap\Plugin\ProviderManager;
  4. use Drupal\bootstrap\Plugin\SettingManager;
  5. use Drupal\bootstrap\Plugin\UpdateManager;
  6. use Drupal\bootstrap\Utility\Crypt;
  7. use Drupal\bootstrap\Utility\Storage;
  8. use Drupal\bootstrap\Utility\StorageItem;
  9. use Drupal\Core\Extension\Extension;
  10. use Drupal\Core\Extension\ThemeHandlerInterface;
  11. use Drupal\Core\Site\Settings;
  12. use Drupal\Core\Url;
  13. /**
  14. * Defines a theme object.
  15. *
  16. * @ingroup utility
  17. */
  18. class Theme {
  19. /**
  20. * Ignores the following directories during file scans of a theme.
  21. *
  22. * @see \Drupal\bootstrap\Theme::IGNORE_ASSETS
  23. * @see \Drupal\bootstrap\Theme::IGNORE_CORE
  24. * @see \Drupal\bootstrap\Theme::IGNORE_DOCS
  25. * @see \Drupal\bootstrap\Theme::IGNORE_DEV
  26. */
  27. const IGNORE_DEFAULT = -1;
  28. /**
  29. * Ignores the directories "assets", "css", "images" and "js".
  30. */
  31. const IGNORE_ASSETS = 0x1;
  32. /**
  33. * Ignores the directories "config", "lib" and "src".
  34. */
  35. const IGNORE_CORE = 0x2;
  36. /**
  37. * Ignores the directories "docs" and "documentation".
  38. */
  39. const IGNORE_DOCS = 0x4;
  40. /**
  41. * Ignores "bower_components", "grunt", "node_modules" and "starterkits".
  42. */
  43. const IGNORE_DEV = 0x8;
  44. /**
  45. * Ignores the directories "templates" and "theme".
  46. */
  47. const IGNORE_TEMPLATES = 0x16;
  48. /**
  49. * Flag indicating if the theme is Bootstrap based.
  50. *
  51. * @var bool
  52. */
  53. protected $bootstrap;
  54. /**
  55. * A list of available CDN Provider instances.
  56. *
  57. * @var \Drupal\bootstrap\Plugin\Provider\ProviderInterface[]
  58. */
  59. protected $cdnProviders;
  60. /**
  61. * Flag indicating if the theme is in "development" mode.
  62. *
  63. * @var bool
  64. *
  65. * This property can only be set via `settings.local.php`:
  66. *
  67. * @code
  68. * $settings['theme.dev'] = TRUE;
  69. * @endcode
  70. */
  71. protected $dev;
  72. /**
  73. * The current theme info.
  74. *
  75. * @var array
  76. */
  77. protected $info;
  78. /**
  79. * A URL for where a livereload instance is listening, if set.
  80. *
  81. * @var string
  82. *
  83. * This property can only be set via `settings.local.php`:
  84. *
  85. * @code
  86. * // Enable default value: //127.0.0.1:35729/livereload.js.
  87. * $settings['theme.livereload'] = TRUE;
  88. *
  89. * // Or, set just the port number: //127.0.0.1:12345/livereload.js.
  90. * $settings['theme.livereload'] = 12345;
  91. *
  92. * // Or, Set an explicit URL.
  93. * $settings['theme.livereload'] = '//127.0.0.1:35729/livereload.js';
  94. * @endcode
  95. */
  96. protected $livereload;
  97. /**
  98. * The theme machine name.
  99. *
  100. * @var string
  101. */
  102. protected $name;
  103. /**
  104. * An array of Setting instances.
  105. *
  106. * @var \Drupal\bootstrap\Plugin\Setting\SettingInterface[]
  107. */
  108. protected $settings;
  109. /**
  110. * The current theme Extension object.
  111. *
  112. * @var \Drupal\Core\Extension\Extension
  113. */
  114. protected $theme;
  115. /**
  116. * An array of installed themes.
  117. *
  118. * @var array
  119. */
  120. protected $themes;
  121. /**
  122. * Theme handler object.
  123. *
  124. * @var \Drupal\Core\Extension\ThemeHandlerInterface
  125. */
  126. protected $themeHandler;
  127. /**
  128. * The update plugin manager.
  129. *
  130. * @var \Drupal\bootstrap\Plugin\UpdateManager
  131. */
  132. protected $updateManager;
  133. /**
  134. * Theme constructor.
  135. *
  136. * @param \Drupal\Core\Extension\Extension $theme
  137. * A theme \Drupal\Core\Extension\Extension object.
  138. * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
  139. * The theme handler object.
  140. */
  141. public function __construct(Extension $theme, ThemeHandlerInterface $theme_handler) {
  142. // Determine if "development mode" is set.
  143. $this->dev = !!Settings::get('theme.dev');
  144. // Determine the URL for livereload, if set.
  145. $this->livereload = '';
  146. if ($livereload = Settings::get('theme.livereload')) {
  147. // If TRUE, then set the port to the default used by grunt-contrib-watch.
  148. if ($livereload === TRUE) {
  149. $livereload = '//127.0.0.1:35729/livereload.js';
  150. }
  151. // If an integer, assume it's a port.
  152. elseif (is_int($livereload)) {
  153. $livereload = "//127.0.0.1:$livereload/livereload.js";
  154. }
  155. // If it's scalar, attempt to parse the URL.
  156. elseif (is_scalar($livereload)) {
  157. try {
  158. $livereload = Url::fromUri($livereload)->toString();
  159. }
  160. catch (\Exception $e) {
  161. $livereload = '';
  162. }
  163. }
  164. // Typecast livereload URL to a string.
  165. $this->livereload = "$livereload" ?: '';
  166. }
  167. $this->name = $theme->getName();
  168. $this->theme = $theme;
  169. $this->themeHandler = $theme_handler;
  170. $this->themes = $this->themeHandler->listInfo();
  171. $this->info = isset($this->themes[$this->name]->info) ? $this->themes[$this->name]->info : [];
  172. $this->bootstrap = $this->subthemeOf('bootstrap');
  173. // Only install the theme if it's Bootstrap based and there are no schemas
  174. // currently set.
  175. if ($this->isBootstrap() && !$this->getSetting('schemas')) {
  176. try {
  177. $this->install();
  178. }
  179. catch (\Exception $e) {
  180. // Intentionally left blank.
  181. // @see https://www.drupal.org/node/2697075
  182. }
  183. }
  184. }
  185. /**
  186. * Serialization method.
  187. */
  188. public function __sleep() {
  189. // Only store the theme name.
  190. return ['name'];
  191. }
  192. /**
  193. * Unserialize method.
  194. */
  195. public function __wakeup() {
  196. $theme_handler = Bootstrap::getThemeHandler();
  197. $theme = $theme_handler->getTheme($this->name);
  198. $this->__construct($theme, $theme_handler);
  199. }
  200. /**
  201. * Returns the theme machine name.
  202. *
  203. * @return string
  204. * Theme machine name.
  205. */
  206. public function __toString() {
  207. return $this->getName();
  208. }
  209. /**
  210. * Retrieves the theme's settings array appropriate for drupalSettings.
  211. *
  212. * @return array
  213. * The theme settings for drupalSettings.
  214. */
  215. public function drupalSettings() {
  216. // Immediately return if theme is not Bootstrap based.
  217. if (!$this->isBootstrap()) {
  218. return [];
  219. }
  220. $cache = $this->getCache('drupalSettings');
  221. $drupal_settings = $cache->getAll();
  222. if (!$drupal_settings) {
  223. foreach ($this->getSettingPlugin() as $name => $setting) {
  224. if ($setting->drupalSettings()) {
  225. $drupal_settings[$name] = TRUE;
  226. }
  227. }
  228. $cache->setMultiple($drupal_settings);
  229. }
  230. $drupal_settings = array_intersect_key($this->settings()->get(), $drupal_settings);
  231. // Indicate that theme is in dev mode.
  232. if ($this->isDev()) {
  233. $drupal_settings['dev'] = TRUE;
  234. }
  235. return $drupal_settings;
  236. }
  237. /**
  238. * Wrapper for the core file_scan_directory() function.
  239. *
  240. * Finds all files that match a given mask in the given directories and then
  241. * caches the results. A general site cache clear will force new scans to be
  242. * initiated for already cached directories.
  243. *
  244. * @param string $mask
  245. * The preg_match() regular expression of the files to find.
  246. * @param string $subdir
  247. * Sub-directory in the theme to start the scan, without trailing slash. If
  248. * not set, the base path of the current theme will be used.
  249. * @param array $options
  250. * Options to pass, see file_scan_directory() for addition options:
  251. * - ignore_flags: (int|FALSE) A bitmask to indicate which directories (if
  252. * any) should be skipped during the scan. Must also not contain a
  253. * "nomask" property in $options. Value can be any of the following:
  254. * - \Drupal\bootstrap::IGNORE_CORE
  255. * - \Drupal\bootstrap::IGNORE_ASSETS
  256. * - \Drupal\bootstrap::IGNORE_DOCS
  257. * - \Drupal\bootstrap::IGNORE_DEV
  258. * - \Drupal\bootstrap::IGNORE_THEME
  259. * Pass FALSE to iterate over all directories in $dir.
  260. *
  261. * @return array
  262. * An associative array (keyed on the chosen key) of objects with 'uri',
  263. * 'filename', and 'name' members corresponding to the matching files.
  264. *
  265. * @see file_scan_directory()
  266. */
  267. public function fileScan($mask, $subdir = NULL, array $options = []) {
  268. $path = $this->getPath();
  269. // Append addition sub-directories to the path if they were provided.
  270. if (isset($subdir)) {
  271. $path .= '/' . $subdir;
  272. }
  273. // Default ignore flags.
  274. $options += [
  275. 'ignore_flags' => self::IGNORE_DEFAULT,
  276. ];
  277. $flags = $options['ignore_flags'];
  278. if ($flags === self::IGNORE_DEFAULT) {
  279. $flags = self::IGNORE_CORE | self::IGNORE_ASSETS | self::IGNORE_DOCS | self::IGNORE_DEV;
  280. }
  281. // Save effort by skipping directories that are flagged.
  282. if (!isset($options['nomask']) && $flags) {
  283. $ignore_directories = [];
  284. if ($flags & self::IGNORE_ASSETS) {
  285. $ignore_directories += ['assets', 'css', 'images', 'js'];
  286. }
  287. if ($flags & self::IGNORE_CORE) {
  288. $ignore_directories += ['config', 'lib', 'src'];
  289. }
  290. if ($flags & self::IGNORE_DOCS) {
  291. $ignore_directories += ['docs', 'documentation'];
  292. }
  293. if ($flags & self::IGNORE_DEV) {
  294. $ignore_directories += [
  295. 'bower_components',
  296. 'grunt',
  297. 'node_modules',
  298. 'starterkits',
  299. ];
  300. }
  301. if ($flags & self::IGNORE_TEMPLATES) {
  302. $ignore_directories += ['templates', 'theme'];
  303. }
  304. if (!empty($ignore_directories)) {
  305. $options['nomask'] = '/^' . implode('|', $ignore_directories) . '$/';
  306. }
  307. }
  308. // Retrieve cache.
  309. $cache = $this->getCache('files');
  310. // Generate a unique hash for all parameters passed as a change in any of
  311. // them could potentially return different results.
  312. $hash = Crypt::generateBase64HashIdentifier($options, [$mask, $path]);
  313. if (!$cache->has($hash)) {
  314. if ($fileSystem = Bootstrap::fileSystem('scanDirectory')) {
  315. $files = $fileSystem->scanDirectory($path, $mask, $options);
  316. }
  317. else {
  318. $files = file_scan_directory($path, $mask, $options);
  319. }
  320. $cache->set($hash, $files);
  321. }
  322. return $cache->get($hash, []);
  323. }
  324. /**
  325. * Retrieves the full base/sub-theme ancestry of a theme.
  326. *
  327. * @param bool $reverse
  328. * Whether or not to return the array of themes in reverse order, where the
  329. * active theme is the first entry.
  330. *
  331. * @return \Drupal\bootstrap\Theme[]
  332. * An associative array of \Drupal\bootstrap objects (theme), keyed
  333. * by machine name.
  334. */
  335. public function getAncestry($reverse = FALSE) {
  336. $ancestry = $this->themeHandler->getBaseThemes($this->themes, $this->getName());
  337. foreach (array_keys($ancestry) as $name) {
  338. $ancestry[$name] = Bootstrap::getTheme($name, $this->themeHandler);
  339. }
  340. $ancestry[$this->getName()] = $this;
  341. return $reverse ? array_reverse($ancestry) : $ancestry;
  342. }
  343. /**
  344. * Retrieves an individual item from a theme's cache in the database.
  345. *
  346. * @param string $name
  347. * The name of the item to retrieve from the theme cache.
  348. * @param array $context
  349. * Optional. An array of additional context to use for retrieving the
  350. * cached storage.
  351. * @param mixed $default
  352. * Optional. The default value to use if $name does not exist.
  353. *
  354. * @return mixed|\Drupal\bootstrap\Utility\StorageItem
  355. * The cached value for $name.
  356. */
  357. public function getCache($name, array $context = [], $default = []) {
  358. static $cache = [];
  359. // Prepend the theme name as the first context item, followed by cache name.
  360. array_unshift($context, $name);
  361. array_unshift($context, $this->getName());
  362. // Join context together with ":" and use it as the name.
  363. $name = implode(':', $context);
  364. if (!isset($cache[$name])) {
  365. $storage = self::getStorage();
  366. $value = $storage->get($name);
  367. if (!isset($value)) {
  368. $value = is_array($default) ? new StorageItem($default, $storage) : $default;
  369. $storage->set($name, $value);
  370. }
  371. $cache[$name] = $value;
  372. }
  373. return $cache[$name];
  374. }
  375. /**
  376. * Retrieves the set CDN Provider instance for the theme.
  377. *
  378. * @return \Drupal\bootstrap\Plugin\Provider\ProviderInterface
  379. * A CDN Provider instance.
  380. */
  381. public function getCdnProvider() {
  382. $provider = $this->getSetting('cdn_provider');
  383. $providers = $this->getCdnProviders();
  384. return isset($providers[$provider]) ? $providers[$provider] : ProviderManager::broken();
  385. }
  386. /**
  387. * Retrieves all available CDN Provider instances.
  388. *
  389. * @return \Drupal\bootstrap\Plugin\Provider\ProviderInterface[]
  390. * All CDN Provider instances.
  391. */
  392. public function getCdnProviders() {
  393. if (!isset($this->cdnProviders)) {
  394. $this->cdnProviders = [];
  395. // Only continue if the theme is Bootstrap based.
  396. if ($this->isBootstrap()) {
  397. $provider_manager = new ProviderManager($this);
  398. foreach ($provider_manager->getDefinitions() as $provider => $definition) {
  399. // Ignore hidden providers.
  400. if (!empty($definition['hidden'])) {
  401. continue;
  402. }
  403. $this->cdnProviders[$provider] = $provider_manager->get($provider, ['theme' => $this]);
  404. }
  405. }
  406. }
  407. return $this->cdnProviders;
  408. }
  409. /**
  410. * Retrieves the theme info.
  411. *
  412. * @param string $property
  413. * A specific property entry from the theme's info array to return.
  414. *
  415. * @return array
  416. * The entire theme info or a specific item if $property was passed.
  417. */
  418. public function getInfo($property = NULL) {
  419. if (isset($property)) {
  420. return isset($this->info[$property]) ? $this->info[$property] : NULL;
  421. }
  422. return $this->info;
  423. }
  424. /**
  425. * Returns the machine name of the theme.
  426. *
  427. * @return string
  428. * The machine name of the theme.
  429. */
  430. public function getName() {
  431. return $this->theme->getName();
  432. }
  433. /**
  434. * Returns the relative path of the theme.
  435. *
  436. * @return string
  437. * The relative path of the theme.
  438. */
  439. public function getPath() {
  440. return $this->theme->getPath();
  441. }
  442. /**
  443. * Retrieves pending updates for the theme.
  444. *
  445. * @return \Drupal\bootstrap\Plugin\Update\UpdateInterface[]
  446. * An array of update plugin objects.
  447. */
  448. public function getPendingUpdates() {
  449. $pending = [];
  450. // Only continue if the theme is Bootstrap based.
  451. if ($this->isBootstrap()) {
  452. $current_theme = $this->getName();
  453. $schemas = $this->getSetting('schemas', []);
  454. foreach ($this->getAncestry() as $ancestor) {
  455. $ancestor_name = $ancestor->getName();
  456. if (!isset($schemas[$ancestor_name])) {
  457. $schemas[$ancestor_name] = \Drupal::CORE_MINIMUM_SCHEMA_VERSION;
  458. $this->setSetting('schemas', $schemas);
  459. }
  460. $pending_updates = $ancestor->getUpdateManager()->getPendingUpdates($current_theme === $ancestor_name);
  461. foreach ($pending_updates as $schema => $update) {
  462. if ((int) $schema > (int) $schemas[$ancestor_name]) {
  463. $pending[] = $update;
  464. }
  465. }
  466. }
  467. }
  468. return $pending;
  469. }
  470. /**
  471. * Retrieves a theme setting.
  472. *
  473. * @param string $name
  474. * The name of the setting to be retrieved.
  475. * @param mixed $default
  476. * A default value to provide if the setting is not found or if the plugin
  477. * does not have a "defaultValue" annotation key/value pair. Typically,
  478. * you will likely never need to use this unless in rare circumstances
  479. * where the setting plugin exists but needs a default value not able to
  480. * be set by conventional means (e.g. empty array).
  481. *
  482. * @return mixed
  483. * The value of the requested setting, NULL if the setting does not exist
  484. * and no $default value was provided.
  485. *
  486. * @see theme_get_setting()
  487. */
  488. public function getSetting($name, $default = NULL) {
  489. $value = $this->settings()->get($name);
  490. return !isset($value) ? $default : $value;
  491. }
  492. /**
  493. * Retrieves a theme's setting plugin instance(s).
  494. *
  495. * @param string $name
  496. * Optional. The name of a specific setting plugin instance to return.
  497. * @param bool $rebuild
  498. * Flag indicating whether to reset any cached definitions and rebuild
  499. * the settings.
  500. *
  501. * @return \Drupal\bootstrap\Plugin\Setting\SettingInterface|\Drupal\bootstrap\Plugin\Setting\SettingInterface[]|null
  502. * If $name was provided, it will either return a specific setting plugin
  503. * instance or NULL if not set. If $name was omitted it will return an array
  504. * of setting plugin instances, keyed by their name.
  505. */
  506. public function getSettingPlugin($name = NULL, $rebuild = FALSE) {
  507. if (!isset($this->settings) || $rebuild) {
  508. $settings = [];
  509. if ($this->isBootstrap()) {
  510. $setting_manager = new SettingManager($this);
  511. if ($rebuild) {
  512. $setting_manager->clearCachedDefinitions();
  513. }
  514. $plugin_ids = array_keys($setting_manager->getDefinitions());
  515. foreach ($plugin_ids as $plugin_id) {
  516. $settings[$plugin_id] = $setting_manager->createInstance($plugin_id);
  517. }
  518. }
  519. $this->settings = $settings;
  520. }
  521. // Return a specific setting plugin.
  522. if (isset($name)) {
  523. return isset($this->settings[$name]) ? $this->settings[$name] : NULL;
  524. }
  525. // Return all setting plugins.
  526. return $this->settings;
  527. }
  528. /**
  529. * Retrieves the theme's cache from the database.
  530. *
  531. * @return \Drupal\bootstrap\Utility\Storage
  532. * The cache object.
  533. */
  534. public function getStorage() {
  535. static $cache = [];
  536. $theme = $this->getName();
  537. if (!isset($cache[$theme])) {
  538. $cache[$theme] = new Storage($theme);
  539. }
  540. return $cache[$theme];
  541. }
  542. /**
  543. * Retrieves the human-readable title of the theme.
  544. *
  545. * @return string
  546. * The theme title or machine name as a fallback.
  547. */
  548. public function getTitle() {
  549. return $this->getInfo('name') ?: $this->getName();
  550. }
  551. /**
  552. * Retrieves the update plugin manager for the theme.
  553. *
  554. * @return \Drupal\bootstrap\Plugin\UpdateManager|false
  555. * The Update plugin manager or FALSE if theme is not Bootstrap based.
  556. */
  557. public function getUpdateManager() {
  558. // Immediately return if theme is not Bootstrap based.
  559. if (!$this->isBootstrap()) {
  560. return FALSE;
  561. }
  562. if (!$this->updateManager) {
  563. $this->updateManager = new UpdateManager($this);
  564. }
  565. return $this->updateManager;
  566. }
  567. /**
  568. * Determines whether or not if the theme has Bootstrap Framework Glyphicons.
  569. */
  570. public function hasGlyphicons() {
  571. $glyphicons = $this->getCache('glyphicons');
  572. if (!$glyphicons->has($this->getName())) {
  573. $exists = FALSE;
  574. foreach ($this->getAncestry(TRUE) as $ancestor) {
  575. if ($ancestor->getSetting('cdn_provider') || $ancestor->fileScan('/glyphicons-halflings-regular\.(eot|svg|ttf|woff)$/', NULL, ['ignore_flags' => FALSE])) {
  576. $exists = TRUE;
  577. break;
  578. }
  579. }
  580. $glyphicons->set($this->getName(), $exists);
  581. }
  582. return $glyphicons->get($this->getName(), FALSE);
  583. }
  584. /**
  585. * Includes a file from the theme.
  586. *
  587. * @param string $file
  588. * The file name, including the extension.
  589. * @param string $path
  590. * The path to the file in the theme. Defaults to: "includes". Set to FALSE
  591. * or and empty string if the file resides in the theme's root directory.
  592. *
  593. * @return bool
  594. * TRUE if the file exists and is included successfully, FALSE otherwise.
  595. */
  596. public function includeOnce($file, $path = 'includes') {
  597. static $includes = [];
  598. $file = preg_replace('`^/?' . $this->getPath() . '/?`', '', $file);
  599. $file = strpos($file, '/') !== 0 ? $file = "/$file" : $file;
  600. $path = is_string($path) && !empty($path) && strpos($path, '/') !== 0 ? $path = "/$path" : '';
  601. $include = DRUPAL_ROOT . '/' . $this->getPath() . $path . $file;
  602. if (!isset($includes[$include])) {
  603. $includes[$include] = [email protected]include_once $include;
  604. if (!$includes[$include]) {
  605. Bootstrap::message(t('Could not include file: @include', ['@include' => $include]), 'error');
  606. }
  607. }
  608. return $includes[$include];
  609. }
  610. /**
  611. * Installs a Bootstrap based theme.
  612. */
  613. protected function install() {
  614. // Immediately return if theme is not Bootstrap based.
  615. if (!$this->isBootstrap()) {
  616. return;
  617. }
  618. $schemas = [];
  619. foreach ($this->getAncestry() as $ancestor) {
  620. $schemas[$ancestor->getName()] = $ancestor->getUpdateManager()->getLatestSchema();
  621. }
  622. $this->setSetting('schemas', $schemas);
  623. }
  624. /**
  625. * Indicates whether the theme is bootstrap based.
  626. *
  627. * @return bool
  628. * TRUE or FALSE
  629. */
  630. public function isBootstrap() {
  631. return $this->bootstrap;
  632. }
  633. /**
  634. * Indicates whether the theme is in "development mode".
  635. *
  636. * @return bool
  637. * TRUE or FALSE
  638. *
  639. * @see \Drupal\bootstrap\Theme::dev
  640. */
  641. public function isDev() {
  642. return $this->dev;
  643. }
  644. /**
  645. * Returns the livereload URL set, if any.
  646. *
  647. * @see \Drupal\bootstrap\Theme::livereload
  648. *
  649. * @return string
  650. * The livereload URL.
  651. */
  652. public function livereloadUrl() {
  653. return $this->livereload;
  654. }
  655. /**
  656. * Removes a theme setting.
  657. *
  658. * @param string $name
  659. * Name of the theme setting to remove.
  660. */
  661. public function removeSetting($name) {
  662. $this->settings()->clear($name)->save();
  663. }
  664. /**
  665. * Sets a value for a theme setting.
  666. *
  667. * @param string $name
  668. * Name of the theme setting.
  669. * @param mixed $value
  670. * Value to associate with the theme setting.
  671. */
  672. public function setSetting($name, $value) {
  673. $this->settings()->set($name, $value)->save();
  674. }
  675. /**
  676. * Retrieves the theme settings instance.
  677. *
  678. * @return \Drupal\bootstrap\ThemeSettings
  679. * All settings.
  680. */
  681. public function settings() {
  682. static $themes = [];
  683. $name = $this->getName();
  684. if (!isset($themes[$name])) {
  685. $themes[$name] = new ThemeSettings($this);
  686. }
  687. return $themes[$name];
  688. }
  689. /**
  690. * Determines whether or not a theme is a sub-theme of another.
  691. *
  692. * @param string|\Drupal\bootstrap\Theme $theme
  693. * The name or theme Extension object to check.
  694. *
  695. * @return bool
  696. * TRUE or FALSE
  697. */
  698. public function subthemeOf($theme) {
  699. return (string) $theme === $this->getName() || in_array($theme, array_keys(self::getAncestry()));
  700. }
  701. /****************************************************************************
  702. *
  703. * Deprecated methods
  704. *
  705. ***************************************************************************/
  706. /**
  707. * Retrieves the CDN Provider.
  708. *
  709. * @param string $provider
  710. * Optional. A CDN Provider name. If not set, defaults to the CDN
  711. * provider set in the theme settings.
  712. *
  713. * @return \Drupal\bootstrap\Plugin\Provider\ProviderInterface|false
  714. * A provider instance or FALSE if no provider is set.
  715. *
  716. * @deprecated in 8.x-3.18, will be removed in a future release.
  717. *
  718. * @see \Drupal\bootstrap\Theme::getCdnProvider()
  719. * @see \Drupal\bootstrap\Plugin\ProviderManager::load()
  720. */
  721. public function getProvider($provider = NULL) {
  722. $provider = $provider ?: $this->getSetting('cdn_provider');
  723. $providers = $this->getProviders();
  724. if (!isset($providers[$provider])) {
  725. return FALSE;
  726. }
  727. return $providers[$provider];
  728. }
  729. /**
  730. * Retrieves all CDN Providers.
  731. *
  732. * @return \Drupal\bootstrap\Plugin\Provider\ProviderInterface[]
  733. * All provider instances.
  734. *
  735. * @deprecated in 8.x-3.18, will be removed in a future release.
  736. *
  737. * @see \Drupal\bootstrap\Theme::getCdnProviders()
  738. */
  739. public function getProviders() {
  740. return !$this->isBootstrap() ? [] : $this->getCdnProviders();
  741. }
  742. /**
  743. * Retrieves the theme's setting plugin instances.
  744. *
  745. * @return \Drupal\bootstrap\Plugin\Setting\SettingInterface[]
  746. * An associative array of setting objects, keyed by their name.
  747. *
  748. * @deprecated in 8.x-3.1, will be removed in a future release.
  749. *
  750. * @see \Drupal\bootstrap\Theme::getSettingPlugin()
  751. */
  752. public function getSettingPlugins() {
  753. Bootstrap::deprecated();
  754. return $this->getSettingPlugin();
  755. }
  756. }

Classes

Name Description
Theme Defines a theme object.