Files
Grav/system/src/Grav/Common/Themes.php
2015-09-13 19:25:43 -06:00

234 lines
6.7 KiB
PHP

<?php
namespace Grav\Common;
use Grav\Common\Config\Config;
use Grav\Common\File\CompiledYamlFile;
use Grav\Common\Data\Blueprints;
use Grav\Common\Data\Data;
use RocketTheme\Toolbox\Event\EventDispatcher;
use RocketTheme\Toolbox\Event\EventSubscriberInterface;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* The Themes object holds an array of all the theme objects that Grav knows about.
*
* @author RocketTheme
* @license MIT
*/
class Themes extends Iterator
{
/** @var Grav */
protected $grav;
/** @var Config */
protected $config;
public function __construct(Grav $grav)
{
$this->grav = $grav;
$this->config = $grav['config'];
}
public function init()
{
/** @var EventDispatcher $events */
$events = $this->grav['events'];
/** @var Themes $themes */
$themes = $this->grav['themes'];
$themes->configure();
try {
$instance = $themes->load();
} catch (\InvalidArgumentException $e) {
throw new \RuntimeException($this->current(). ' theme could not be found');
}
if ($instance instanceof EventSubscriberInterface) {
$events->addSubscriber($instance);
}
$this->grav['theme'] = $instance;
}
/**
* Return list of all theme data with their blueprints.
*
* @return array
*/
public function all()
{
$list = array();
$locator = Grav::instance()['locator'];
$iterator = new \DirectoryIterator($locator->findResource('themes://', false));
/** @var \DirectoryIterator $directory */
foreach ($iterator as $directory) {
if (!$directory->isDir() || $directory->isDot()) {
continue;
}
$type = $directory->getBasename();
$list[$type] = self::get($type);
}
ksort($list);
return $list;
}
/**
* Get theme configuration or throw exception if it cannot be found.
*
* @param string $name
* @return Data
* @throws \RuntimeException
*/
public function get($name)
{
if (!$name) {
throw new \RuntimeException('Theme name not provided.');
}
$blueprints = new Blueprints('themes://');
$blueprint = $blueprints->get("{$name}/blueprints");
$blueprint->name = $name;
// Find thumbnail.
$thumb = "themes://{$name}/thumbnail.jpg";
if (file_exists($thumb)) {
$blueprint->set('thumbnail', $this->grav['base_url'] . "/user/themes/{$name}/thumbnail.jpg");
}
// Load default configuration.
$file = CompiledYamlFile::instance("themes://{$name}/{$name}" . YAML_EXT);
$obj = new Data($file->content(), $blueprint);
// Override with user configuration.
$obj->merge($this->grav['config']->get('themes.' . $name) ?: []);
// Save configuration always to user/config.
$file = CompiledYamlFile::instance("config://themes/{$name}" . YAML_EXT);
$obj->file($file);
return $obj;
}
/**
* Return name of the current theme.
*
* @return string
*/
public function current()
{
return (string) $this->config->get('system.pages.theme');
}
/**
* Load current theme.
*
* @return Theme|object
*/
public function load()
{
// NOTE: ALL THE LOCAL VARIABLES ARE USED INSIDE INCLUDED FILE, DO NOT REMOVE THEM!
$grav = $this->grav;
$config = $this->config;
$name = $this->current();
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];
$file = $locator('theme://theme.php') ?: $locator("theme://{$name}.php");
$inflector = $grav['inflector'];
if ($file) {
// Local variables available in the file: $grav, $config, $name, $file
$class = include $file;
if (!is_object($class)) {
$themeClassFormat = [
'Grav\\Theme\\'.ucfirst($name),
'Grav\\Theme\\'.$inflector->camelize($name)
];
$themeClassName = false;
foreach ($themeClassFormat as $themeClass) {
if (class_exists($themeClass)) {
$themeClassName = $themeClass;
$class = new $themeClassName($grav, $config, $name);
break;
}
}
}
} elseif (!$locator('theme://') && !defined('GRAV_CLI')) {
exit("Theme '$name' does not exist, unable to display page.");
}
if (empty($class)) {
$class = new Theme($grav, $config, $name);
}
return $class;
}
/**
* Configure and prepare streams for current template.
*
* @throws \InvalidArgumentException
*/
public function configure()
{
$name = $this->current();
$config = $this->config;
$this->loadConfiguration($name, $config);
/** @var UniformResourceLocator $locator */
$locator = $this->grav['locator'];
$registered = stream_get_wrappers();
$schemes = $config->get(
"themes.{$name}.streams.schemes",
['theme' => ['paths' => $locator->findResources("themes://{$name}", false)]]
);
foreach ($schemes as $scheme => $config) {
if (isset($config['paths'])) {
$locator->addPath($scheme, '', $config['paths']);
}
if (isset($config['prefixes'])) {
foreach ($config['prefixes'] as $prefix => $paths) {
$locator->addPath($scheme, $prefix, $paths);
}
}
if (in_array($scheme, $registered)) {
stream_wrapper_unregister($scheme);
}
$type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
if ($type[0] != '\\') {
$type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
}
if (!stream_wrapper_register($scheme, $type)) {
throw new \InvalidArgumentException("Stream '{$type}' could not be initialized.");
}
}
}
protected function loadConfiguration($name, Config $config)
{
$themeConfig = CompiledYamlFile::instance("themes://{$name}/{$name}" . YAML_EXT)->content();
$config->joinDefaults("themes.{$name}", $themeConfig);
if ($this->config->get('system.languages.translations', true)) {
$languages = CompiledYamlFile::instance("themes://{$name}/languages". YAML_EXT)->content();
if ($languages) {
$config->getLanguages()->mergeRecursive($languages);
}
}
}
}