diff --git a/bin/grav b/bin/grav index e886be322..344bef6f0 100755 --- a/bin/grav +++ b/bin/grav @@ -3,7 +3,12 @@ use Symfony\Component\Console\Application; -require_once(__DIR__ . '/../vendor/autoload.php'); +$autoload = __DIR__ . '/../vendor/autoload.php'; +if (!is_file($autoload)) { + exit('Please run: composer install -o'); +} + +require_once $autoload; if (!ini_get('date.timezone')) { date_default_timezone_set('UTC'); diff --git a/composer.json b/composer.json index 020e0b149..966669941 100644 --- a/composer.json +++ b/composer.json @@ -18,8 +18,15 @@ "ircmaxell/password-compat": "1.0.*", "mrclay/minify": "~2.2", "ornicar/php-user-agent": "1.0.*", - "pimple/pimple": "~3.0" + "pimple/pimple": "~3.0", + "rockettheme/toolbox": "dev-develop" }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/rockettheme/toolbox" + } + ], "autoload": { "psr-4": { "Grav\\": "system/src/" diff --git a/system/blueprints/media.yaml b/system/blueprints/config/media.yaml similarity index 100% rename from system/blueprints/media.yaml rename to system/blueprints/config/media.yaml diff --git a/system/blueprints/site.yaml b/system/blueprints/config/site.yaml similarity index 100% rename from system/blueprints/site.yaml rename to system/blueprints/config/site.yaml diff --git a/system/blueprints/config/streams.yaml b/system/blueprints/config/streams.yaml new file mode 100644 index 000000000..e6a199320 --- /dev/null +++ b/system/blueprints/config/streams.yaml @@ -0,0 +1,7 @@ +title: File Streams +validation: loose + +form: + fields: + schemes.xxx: + type: array diff --git a/system/blueprints/system.yaml b/system/blueprints/config/system.yaml similarity index 100% rename from system/blueprints/system.yaml rename to system/blueprints/config/system.yaml diff --git a/system/blueprints/page.yaml b/system/blueprints/page/page.yaml similarity index 100% rename from system/blueprints/page.yaml rename to system/blueprints/page/page.yaml diff --git a/system/config/streams.yaml b/system/config/streams.yaml index 0ab5c3f8b..039c5eb5f 100644 --- a/system/config/streams.yaml +++ b/system/config/streams.yaml @@ -1,10 +1,4 @@ schemes: - plugin: - type: ReadOnlyStream - paths: - - user/plugins - - system/plugins - user: type: ReadOnlyStream paths: @@ -15,21 +9,6 @@ schemes: # paths: # - assets -# cache: -# type: ReadOnlyStream -# paths: -# - cache - -# log: -# type: ReadOnlyStream -# paths: -# - logs - - page: - type: ReadOnlyStream - paths: - - user/pages - account: type: ReadOnlyStream paths: @@ -39,3 +18,21 @@ schemes: type: ReadOnlyStream paths: - user/data + + page: + type: ReadOnlyStream + prefixes: + '/': + - user/pages + + image: + prefixes: + '/': + - user/images + - system/images + + theme: + prefixes: + '/': + - user/themes + - system/themes diff --git a/system/defines.php b/system/defines.php index 7cc877e6f..99cd5202a 100644 --- a/system/defines.php +++ b/system/defines.php @@ -6,10 +6,10 @@ define('GRAV_VERSION', '0.8.1'); define('DS', '/'); // Directories and Paths -if (!defined('ROOT_DIR')) { - define('ROOT_DIR', getcwd() .'/'); +if (!defined('GRAV_ROOT')) { + define('GRAV_ROOT', getcwd()); } -define('GRAV_ROOT', ROOT_DIR); +define('ROOT_DIR', GRAV_ROOT . '/'); define('USER_PATH', 'user/'); define('USER_DIR', ROOT_DIR . USER_PATH); define('SYSTEM_DIR', ROOT_DIR .'system/'); diff --git a/system/src/Grav/Common/Config.php b/system/src/Grav/Common/Config.php deleted file mode 100644 index df25af870..000000000 --- a/system/src/Grav/Common/Config.php +++ /dev/null @@ -1,259 +0,0 @@ -filename = realpath(dirname($filename)) . '/' . basename($filename); - - $this->reload(false); - } - - /** - * Force reload of the configuration from the disk. - * - * @param bool $force - * @return $this - */ - public function reload($force = true) - { - // Build file map. - $files = $this->build(); - $key = md5(serialize($files) . GRAV_VERSION); - - if ($force || $key != $this->key) { - // First take non-blocking lock to the file. - File\Config::instance($this->filename)->lock(false); - - // Reset configuration. - $this->items = array(); - $this->files = array(); - $this->init($files); - $this->key = $key; - } - - return $this; - } - - /** - * Save configuration into file. - * - * Note: Only saves the file if updated flag is set! - * - * @return $this - * @throws \RuntimeException - */ - public function save() - { - // If configuration was updated, store it as cached version. - try { - $file = File\Config::instance($this->filename); - - // Only save configuration file if it wasn't locked. Also invalidate opcache after saving. - // This prevents us from saving the file multiple times in a row and gives faster recovery. - if ($file->locked() !== false) { - $file->save($this); - $file->unlock(); - } - $this->updated = false; - } catch (\Exception $e) { - $this->issues[] = 'Writing configuration into cache failed.'; - //throw new \RuntimeException('Writing configuration into cache failed.', 500, $e); - } - - return $this; - } - - /** - * Load configuration. - * - * @param Grav $grav - * @return \Grav\Common\Config - */ - public static function instance(Grav $grav) - { - $filename = $grav['config_path']; - - // Load cached version if available.. - if (file_exists($filename)) { - require_once $filename; - - if (class_exists('\Grav\Config')) { - $instance = new \Grav\Config($filename); - } - } - - // Or initialize new configuration object.. - if (!isset($instance)) { - $instance = new static($filename); - } - - // If configuration was updated, store it as cached version. - if ($instance->updated) { - $instance->save(); - } - - - // If not set, add manually current base url. - if (empty($instance->items['system']['base_url_absolute'])) { - $instance->items['system']['base_url_absolute'] = $grav['uri']->rootUrl(true); - } - - if (empty($instance->items['system']['base_url_relative'])) { - $instance->items['system']['base_url_relative'] = $grav['uri']->rootUrl(false); - } - - return $instance; - } - - /** - * Convert configuration into an array. - * - * @return array - */ - public function toArray() - { - return array('key' => $this->key, 'files' => $this->files, 'items' => $this->items); - } - - /** - * Initialize object by loading all the configuration files. - * - * @param array $files - */ - protected function init(array $files) - { - $this->updated = true; - - // Combine all configuration files into one larger lookup table (only keys matter). - $allFiles = $files['user'] + $files['plugins'] + $files['system']; - - // Then sort the files to have all parent nodes first. - // This is to make sure that child nodes override parents content. - uksort( - $allFiles, - function($a, $b) { - $diff = substr_count($a, '/') - substr_count($b, '/'); - return $diff ? $diff : strcmp($a, $b); - } - ); - - $systemBlueprints = new Blueprints(SYSTEM_DIR . 'blueprints'); - $pluginBlueprints = new Blueprints(USER_DIR); - - $items = array(); - foreach ($allFiles as $name => $dummy) { - $lookup = array( - 'system' => SYSTEM_DIR . 'config/' . $name . YAML_EXT, - 'plugins' => USER_DIR . $name . '/' . basename($name) . YAML_EXT, - 'user' => USER_DIR . 'config/' . $name . YAML_EXT, - ); - if (strpos($name, 'plugins/') === 0) { - $blueprint = $pluginBlueprints->get("{$name}/blueprints"); - } else { - $blueprint = $systemBlueprints->get($name); - } - - $data = new Data(array(), $blueprint); - foreach ($lookup as $key => $path) { - if (is_file($path)) { - $data->merge(File\Yaml::instance($path)->content()); - } - } -// $data->validate(); -// $data->filter(); - - // Find the current sub-tree location. - $current = &$items; - $parts = explode('/', $name); - foreach ($parts as $part) { - if (!isset($current[$part])) { - $current[$part] = array(); - } - $current = &$current[$part]; - } - - // Handle both updated and deleted configuration files. - $current = $data->toArray(); - } - - $this->items = $items; - $this->files = $files; - } - - /** - * Build a list of configuration files with their timestamps. Used for loading settings and caching them. - * - * @return array - * @internal - */ - protected function build() - { - // Find all plugins with default configuration options. - $plugins = array(); - $iterator = new \DirectoryIterator(PLUGINS_DIR); - - /** @var \DirectoryIterator $plugin */ - foreach ($iterator as $plugin) { - $name = $plugin->getBasename(); - $file = $plugin->getPathname() . DS . $name . YAML_EXT; - - if (!is_file($file)) { - continue; - } - - $modified = filemtime($file); - $plugins["plugins/{$name}"] = $modified; - } - - // Find all system and user configuration files. - $options = array( - 'compare' => 'Filename', - 'pattern' => '|\.yaml$|', - 'filters' => array('key' => '|\.yaml$|'), - 'key' => 'SubPathname', - 'value' => 'MTime' - ); - - $system = Folder::all(SYSTEM_DIR . 'config', $options); - $user = Folder::all(USER_DIR . 'config', $options); - - return array('system' => $system, 'plugins' => $plugins, 'user' => $user); - } -} diff --git a/system/src/Grav/Common/Config/Blueprints.php b/system/src/Grav/Common/Config/Blueprints.php new file mode 100644 index 000000000..947ff63df --- /dev/null +++ b/system/src/Grav/Common/Config/Blueprints.php @@ -0,0 +1,207 @@ +grav = $grav ?: Grav::instance(); + } + + public function init() + { + /** @var ResourceLocator $locator */ + $locator = $this->grav['locator']; + + $blueprints = $locator->findResources('blueprints:///config'); + $plugins = $locator->findResources('plugin:///'); + + $blueprintFiles = $this->getBlueprintFiles($blueprints, $plugins); + + $this->loadCompiledBlueprints($plugins + $blueprints, $blueprintFiles); + } + + protected function loadCompiledBlueprints($blueprints, $blueprintFiles) + { + $checksum = md5(serialize($blueprints)); + $filename = CACHE_DIR . 'compiled/blueprints/' . $checksum .'.php'; + $checksum .= ':'.md5(serialize($blueprintFiles)); + $class = get_class($this); + $file = Php::instance($filename); + + if ($file->exists()) { + $cache = $file->exists() ? $file->content() : null; + } else { + $cache = null; + } + + + // Load real file if cache isn't up to date (or is invalid). + if ( + !is_array($cache) + || empty($cache['checksum']) + || empty($cache['$class']) + || $cache['checksum'] != $checksum + || $cache['@class'] != $class + ) { + // Attempt to lock the file for writing. + $file->lock(false); + + // Load blueprints. + $this->blueprints = new Blueprints(); + foreach ($blueprintFiles as $key => $files) { + $this->loadBlueprints($key); + } + + $cache = [ + '@class' => $class, + 'checksum' => $checksum, + 'files' => $blueprintFiles, + 'data' => $this->blueprints->toArray() + ]; + + // If compiled file wasn't already locked by another process, save it. + if ($file->locked() !== false) { + $file->save($cache); + $file->unlock(); + } + } else { + $this->blueprints = new Blueprints($cache['data']); + } + } + + /** + * Load global blueprints. + * + * @param string $key + * @param array $files + */ + public function loadBlueprints($key, array $files = null) + { + if (is_null($files)) { + $files = $this->files[$key]; + } + foreach ($files as $name => $item) { + $file = CompiledYaml::instance($item['file']); + $this->blueprints->embed($name, $file->content(), '/'); + } + } + + /** + * Get all blueprint files (including plugins). + * + * @param array $blueprints + * @param array $plugins + * @return array + */ + protected function getBlueprintFiles(array $blueprints, array $plugins) + { + $list = []; + foreach (array_reverse($plugins) as $folder) { + $list += $this->detectPlugins($folder, true); + } + foreach (array_reverse($blueprints) as $folder) { + $list += $this->detectConfig($folder, true); + } + return $list; + } + + /** + * Detects all plugins with a configuration file and returns last modification time. + * + * @param string $lookup Location to look up from. + * @param bool $blueprints + * @return array + * @internal + */ + protected function detectPlugins($lookup = SYSTEM_DIR, $blueprints = false) + { + $find = $blueprints ? 'blueprints.yaml' : '.yaml'; + $location = $blueprints ? 'blueprintFiles' : 'configFiles'; + $path = trim(Folder::getRelativePath($lookup), '/'); + if (isset($this->{$location}[$path])) { + return [$path => $this->{$location}[$path]]; + } + + $list = []; + + if (is_dir($lookup)) { + $iterator = new \DirectoryIterator($lookup); + + /** @var \DirectoryIterator $directory */ + foreach ($iterator as $directory) { + if (!$directory->isDir() || $directory->isDot()) { + continue; + } + + $name = $directory->getBasename(); + $filename = "{$path}/{$name}/" . ($find && $find[0] != '.' ? $find : $name . $find); + + if (is_file($filename)) { + $list["plugins/{$name}"] = ['file' => $filename, 'modified' => filemtime($filename)]; + } + } + } + + $this->{$location}[$path] = $list; + + return [$path => $list]; + } + + /** + * Detects all plugins with a configuration file and returns last modification time. + * + * @param string $lookup Location to look up from. + * @param bool $blueprints + * @return array + * @internal + */ + protected function detectConfig($lookup = SYSTEM_DIR, $blueprints = false) + { + $location = $blueprints ? 'blueprintFiles' : 'configFiles'; + $path = trim(Folder::getRelativePath($lookup), '/'); + if (isset($this->{$location}[$path])) { + return [$path => $this->{$location}[$path]]; + } + + if (is_dir($lookup)) { + // Find all system and user configuration files. + $options = [ + 'compare' => 'Filename', + 'pattern' => '|\.yaml$|', + 'filters' => [ + 'key' => '|\.yaml$|', + 'value' => function (\RecursiveDirectoryIterator $file) use ($path) { + return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()]; + }], + 'key' => 'SubPathname' + ]; + + $list = Folder::all($lookup, $options); + } else { + $list = []; + } + + $this->{$location}[$path] = $list; + + return [$path => $list]; + } +} diff --git a/system/src/Grav/Common/Config/Config.php b/system/src/Grav/Common/Config/Config.php new file mode 100644 index 000000000..ba43da932 --- /dev/null +++ b/system/src/Grav/Common/Config/Config.php @@ -0,0 +1,414 @@ + [ + 'schemes' => [ + 'blueprints' => [ + 'type' => 'ReadOnlyStream', + 'prefixes' => [ + '/' => ['user/blueprints', 'system/blueprints'], + ] + ], + 'config' => [ + 'type' => 'ReadOnlyStream', + 'prefixes' => [ + '/' => ['user/config', 'system/config'], + ] + ], + 'plugin' => [ + 'type' => 'ReadOnlyStream', + 'prefixes' => [ + '' => ['user/plugins'], + ] + ], + 'cache' => [ + 'type' => 'Stream', + 'prefixes' => [ + '' => ['cache'] + ] + ], + 'logs' => [ + 'type' => 'Stream', + 'prefixes' => [ + '' => ['logs'] + ] + ] + ], + ], + ]; + + protected $blueprintFiles = []; + protected $configFiles = []; + protected $checksum; + protected $timestamp; + + public function __construct(array $items = array(), Grav $grav = null) + { + $this->grav = $grav ?: Grav::instance(); + + if (isset($items['@class']) && $items['@class'] = get_class($this)) { + // Loading pre-compiled configuration. + $this->timestamp = (int) $items['timestamp']; + $this->checksum = (string) $items['checksum']; + $this->items = (array) $items['data']; + } else { + parent::__construct($items + $this->default); + } + } + + public function init() + { + $checksum = $this->checksum(); + if ($checksum == $this->checksum) { + return; + } + + $this->checksum = $checksum; + + /** @var Uri $uri */ + $uri = $this->grav['uri']; + + // If not set, add manually current base url. + $this->def('system.base_url_absolute', $uri->rootUrl(true)); + $this->def('system.base_url_relative', $uri->rootUrl(false)); + + /** @var ResourceLocator $locator */ + $locator = $this->grav['locator']; + $configs = $locator->findResources('config:///'); + $blueprints = $locator->findResources('blueprints:///config'); + $plugins = $locator->findResources('plugin:///'); + + $this->loadCompiledBlueprints($blueprints, $plugins, 'master'); + $this->loadCompiledConfig($configs, $plugins, 'master'); + } + + public function checksum() + { + $checkBlueprints = $this->get('system.cache.check.blueprints', true); + $checkConfig = $this->get('system.cache.check.config', true); + $checkSystem = $this->get('system.cache.check.system', true); + + if (!$checkBlueprints && !$checkConfig && !$checkSystem) { + return false; + } + + /** @var ResourceLocator $locator */ + $locator = $this->grav['locator']; + $configs = $locator->findResources('config:///'); + $blueprints = $locator->findResources('blueprints:///config'); + $plugins = $locator->findResources('plugin:///'); + + // Generate checksum according to the configuration settings. + if (!$checkConfig) { + // Just check changes in system.yaml files and ignore all the other files. + $cc = $checkSystem ? $this->detectFile($configs, 'system') : []; + } else { + // Check changes in all configuration files. + $cc = $this->getConfigFiles($configs, $plugins); + } + $cb = $checkBlueprints ? $this->getBlueprintFiles($blueprints, $plugins) : []; + + return md5(serialize([$cc, $cb])); + } + + protected function loadCompiledBlueprints($blueprints, $plugins, $filename = null) + { + $checksum = md5(serialize($blueprints)); + $filename = $filename + ? CACHE_DIR . 'compiled/blueprints/' . $filename .'.php' + : CACHE_DIR . 'compiled/blueprints/' . $checksum .'.php'; + $file = Php::instance($filename); + + if ($file->exists()) { + $cache = $file->exists() ? $file->content() : null; + } else { + $cache = null; + } + + $blueprintFiles = $this->getBlueprintFiles($blueprints, $plugins); + $checksum .= ':'.md5(serialize($blueprintFiles)); + $class = get_class($this); + + // Load real file if cache isn't up to date (or is invalid). + if ( + !is_array($cache) + || empty($cache['checksum']) + || empty($cache['$class']) + || $cache['checksum'] != $checksum + || $cache['@class'] != $class + ) { + // Attempt to lock the file for writing. + $file->lock(false); + + // Load blueprints. + $this->blueprints = new Blueprints(); + foreach ($blueprintFiles as $key => $files) { + $this->loadBlueprints($key); + } + + $cache = [ + '@class' => $class, + 'checksum' => $checksum, + 'files' => $blueprintFiles, + 'data' => $this->blueprints->toArray() + ]; + + // If compiled file wasn't already locked by another process, save it. + if ($file->locked() !== false) { + $file->save($cache); + $file->unlock(); + } + } else { + $this->blueprints = new Blueprints($cache['data']); + } + } + + protected function loadCompiledConfig($configs, $plugins, $filename = null) + { + $checksum = md5(serialize($configs)); + $filename = $filename + ? CACHE_DIR . 'compiled/config/' . $filename .'.php' + : CACHE_DIR . 'compiled/config/' . $checksum .'.php'; + $file = Php::instance($filename); + + if ($file->exists()) { + $cache = $file->exists() ? $file->content() : null; + } else { + $cache = null; + } + + $configFiles = $this->getConfigFiles($configs, $plugins); + $checksum .= ':'.md5(serialize($configFiles)); + print_r($configFiles); + echo $cache['checksum'].' '.$checksum; + $class = get_class($this); + + // Load real file if cache isn't up to date (or is invalid). + if ( + !is_array($cache) + || $cache['checksum'] != $checksum + || $cache['@class'] != $class + ) { + // Attempt to lock the file for writing. + $file->lock(false); + + // Load configuration. + foreach ($configFiles as $key => $files) { + $this->loadConfig($key); + } + $cache = [ + '@class' => $class, + 'timestamp' => time(), + 'checksum' => $this->checksum, + 'data' => $this->toArray() + ]; + + // If compiled file wasn't already locked by another process, save it. + if ($file->locked() !== false) { + $file->save($cache); + $file->unlock(); + } + } + + $this->items = $cache['data']; + } + + /** + * Load global blueprints. + * + * @param string $key + * @param array $files + */ + public function loadBlueprints($key, array $files = null) + { + if (is_null($files)) { + $files = $this->blueprintFiles[$key]; + } + foreach ($files as $name => $item) { + $file = CompiledYaml::instance($item['file']); + $this->blueprints->embed($name, $file->content(), '/'); + } + } + + /** + * Load global configuration. + * + * @param string $key + * @param array $files + */ + public function loadConfig($key, array $files = null) + { + if (is_null($files)) { + $files = $this->configFiles[$key]; + } + foreach ($files as $name => $item) { + $file = CompiledYaml::instance($item['file']); + $this->join($name, $file->content(), '/'); + } + } + + /** + * Get all blueprint files (including plugins). + * + * @param array $blueprints + * @param array $plugins + * @return array + */ + protected function getBlueprintFiles(array $blueprints, array $plugins) + { + $list = []; + foreach (array_reverse($plugins) as $folder) { + $list += $this->detectPlugins($folder, true); + } + foreach (array_reverse($blueprints) as $folder) { + $list += $this->detectConfig($folder, true); + } + return $list; + } + + /** + * Get all configuration files. + * + * @param array $configs + * @param array $plugins + * @return array + */ + protected function getConfigFiles(array $configs, array $plugins) + { + $list = []; + foreach (array_reverse($plugins) as $folder) { + $list += $this->detectPlugins($folder); + } + foreach (array_reverse($configs) as $folder) { + $list += $this->detectConfig($folder); + } + return $list; + } + + /** + * Detects all plugins with a configuration file and returns last modification time. + * + * @param string $lookup Location to look up from. + * @param bool $blueprints + * @return array + * @internal + */ + protected function detectPlugins($lookup = SYSTEM_DIR, $blueprints = false) + { + $find = $blueprints ? 'blueprints.yaml' : '.yaml'; + $location = $blueprints ? 'blueprintFiles' : 'configFiles'; + $path = trim(Folder::getRelativePath($lookup), '/'); + if (isset($this->{$location}[$path])) { + return [$path => $this->{$location}[$path]]; + } + + $list = []; + + if (is_dir($lookup)) { + $iterator = new \DirectoryIterator($lookup); + + /** @var \DirectoryIterator $directory */ + foreach ($iterator as $directory) { + if (!$directory->isDir() || $directory->isDot()) { + continue; + } + + $name = $directory->getBasename(); + $filename = "{$path}/{$name}/" . ($find && $find[0] != '.' ? $find : $name . $find); + + if (is_file($filename)) { + $list["plugins/{$name}"] = ['file' => $filename, 'modified' => filemtime($filename)]; + } + } + } + + $this->{$location}[$path] = $list; + + return [$path => $list]; + } + + /** + * Detects all plugins with a configuration file and returns last modification time. + * + * @param string $lookup Location to look up from. + * @param bool $blueprints + * @return array + * @internal + */ + protected function detectConfig($lookup = SYSTEM_DIR, $blueprints = false) + { + $location = $blueprints ? 'blueprintFiles' : 'configFiles'; + $path = trim(Folder::getRelativePath($lookup), '/'); + if (isset($this->{$location}[$path])) { + return [$path => $this->{$location}[$path]]; + } + + if (is_dir($lookup)) { + // Find all system and user configuration files. + $options = [ + 'compare' => 'Filename', + 'pattern' => '|\.yaml$|', + 'filters' => [ + 'key' => '|\.yaml$|', + 'value' => function (\RecursiveDirectoryIterator $file) use ($path) { + return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()]; + }], + 'key' => 'SubPathname' + ]; + + $list = Folder::all($lookup, $options); + } else { + $list = []; + } + + $this->{$location}[$path] = $list; + + return [$path => $list]; + } + + /** + * Detects all instances of the file and returns last modification time. + * + * @param string $lookups Locations to look up from. + * @param string $name + * @return array + * @internal + */ + protected function detectFile(array $lookups, $name) + { + $list = []; + $filename = "{$name}.yaml"; + foreach ($lookups as $lookup) { + $path = trim(Folder::getRelativePath($lookup), '/'); + + if (is_file("{$lookup}/{$filename}")) { + $modified = filemtime("{$lookup}/{$filename}"); + } else { + $modified = 0; + } + $list[$path] = [$name => ['file' => "{$path}/{$filename}", 'modified' => $modified]]; + } + + return $list; + } +} diff --git a/system/src/Grav/Common/ConfigBak.php b/system/src/Grav/Common/ConfigBak.php new file mode 100644 index 000000000..3272fcdd0 --- /dev/null +++ b/system/src/Grav/Common/ConfigBak.php @@ -0,0 +1,328 @@ +updated) { + $instance->save(); + } + + return $instance; + } + + /** + * Constructor. + * @param string $filename + * @param string $path + * @param array $data + */ + public function __construct($filename, $path, array $data = null) + { + $this->filename = (string) $filename; + $this->path = (string) $path; + + if ($data) { + $this->key = $data['key']; + $this->files = $data['files']; + $this->items = $data['items']; + } + + $this->reload(false); + print_r($this->getBlueprintFiles()); + print_r($this->getConfigFiles()); + } + + /** + * Force reload of the configuration from the disk. + * + * @param bool $force + * @return $this + */ + public function reload($force = true) + { + // Build file map. + $files = $this->build(); + $key = $this->getKey($files); + + if ($force || $key != $this->key) { + // First take non-blocking lock to the file. + File\Php::instance($this->filename)->lock(false); + + // Reset configuration. + $this->items = array(); + $this->files = array(); + $this->init($files); + $this->key = $key; + } + + return $this; + } + + /** + * Save configuration into file. + * + * Note: Only saves the file if updated flag is set! + * + * @return $this + * @throws \RuntimeException + */ + public function save() + { + // If configuration was updated, store it as cached version. + try { + $file = File\Php::instance($this->filename); + + // Only save configuration file if it was successfully locked to prevent multiple saves. + if ($file->locked() !== false) { + $file->save($this->toArray()); + $file->unlock(); + } + $this->updated = false; + } catch (\Exception $e) { + // TODO: do not require saving to succeed, but display some kind of error anyway. + throw new \RuntimeException('Writing configuration to cache folder failed.', 500, $e); + } + + return $this; + } + + /** + * Convert configuration into an array. + * + * @return array + */ + public function toArray() + { + return [ + '@class' => get_class($this), + 'key' => $this->key, + 'files' => $this->files, + 'items' => $this->items + ]; + } + + /** + * @param $files + * @return string + */ + protected function getKey(&$files) + { + return md5(serialize($files) . GRAV_VERSION); + } + + /** + * Initialize object by loading all the configuration files. + * + * @param array $files + */ + protected function init(array $files) + { + $this->updated = true; + + // Then sort the files to have all parent nodes first. + // This is to make sure that child nodes override parents content. + uksort( + $files, + function($a, $b) { + $diff = substr_count($a, '/') - substr_count($b, '/'); + return $diff ? $diff : strcmp($a, $b); + } + ); + + $blueprints = new Blueprints($this->path . '/blueprints/config'); + + $items = array(); + foreach ($files as $name => $dummy) { + $lookup = $this->path . '/config/' . $name . '.yaml'; + $blueprint = $blueprints->get($name); + + $data = new Data(array(), $blueprint); + if (is_file($lookup)) { + $data->merge(File\Yaml::instance($lookup)->content()); + } + + // Find the current sub-tree location. + $current = &$items; + $parts = explode('/', $name); + foreach ($parts as $part) { + if (!isset($current[$part])) { + $current[$part] = array(); + } + $current = &$current[$part]; + } + + // Handle both updated and deleted configuration files. + $current = $data->toArray(); + } + + $this->items = $items; + $this->files = $files; + } + + /** + * Build a list of configuration files with their timestamps. Used for loading settings and caching them. + * + * @return array + * @internal + */ + protected function build() + { + // Find all system and user configuration files. + $options = [ + 'compare' => 'Filename', + 'pattern' => '|\.yaml$|', + 'filters' => ['key' => '|\.yaml$|'], + 'key' => 'SubPathname', + 'value' => 'MTime' + ]; + + return Folder::all($this->path . '/config', $options); + } + + /** + * Detects all plugins with a configuration file and returns last modification time. + * + * @param string $lookup Location to look up from. + * @param string $find Filename or extension to find. + * @return array + */ + protected function detectPlugins($lookup = SYSTEM_DIR, $find = '.yaml') + { + if (!is_dir($lookup)) { + return []; + } + + $list = []; + $iterator = new \DirectoryIterator($lookup); + $path = trim(Folder::getRelativePath($lookup), '/'); + + /** @var \DirectoryIterator $directory */ + foreach ($iterator as $directory) { + if (!$directory->isDir() || $directory->isDot()) { + continue; + } + + $name = $directory->getBasename(); + $filename = "{$path}/{$name}/" . ($find && $find[0] != '.' ? $find : $name . $find); + + if (is_file($filename)) { + $list["plugins/{$name}"] = ['file' => $filename, 'mtime' => filemtime($filename)]; + } + } + + return [$path => $list]; + } + + /** + * Detects all plugins with a configuration file and returns last modification time. + * + * @param string $lookup Location to look up from. + * @return array + */ + protected function detectConfig($lookup = SYSTEM_DIR) + { + if (!is_dir($lookup)) { + return []; + } + + $path = trim(Folder::getRelativePath($lookup), '/'); + + // Find all system and user configuration files. + $options = [ + 'compare' => 'Filename', + 'pattern' => '|\.yaml$|', + 'filters' => [ + 'key' => '|\.yaml$|', + 'value' => function (\RecursiveDirectoryIterator $file) use ($path) { + return ['file' => "{$path}/{$file->getSubPathname()}", 'mtime' => $file->getMTime()]; + }], + 'key' => 'SubPathname' + ]; + + $list = Folder::all($lookup, $options); + return [$path => $list]; + } + + public function getBlueprintFiles() + { + $list = []; + $list += $this->detectPlugins(SYSTEM_DIR . 'plugins', 'blueprints.yaml'); + $list += $this->detectConfig(SYSTEM_DIR . 'blueprints/config'); + $list += $this->detectPlugins(PLUGINS_DIR, 'blueprints.yaml'); + $list += $this->detectConfig(USER_DIR . 'blueprints/config'); + return $list; + } + + public function getConfigFiles() + { + $list = []; + $list += $this->detectPlugins(SYSTEM_DIR . 'plugins'); + $list += $this->detectConfig(SYSTEM_DIR . 'config'); + $list += $this->detectPlugins(PLUGINS_DIR); + $list += $this->detectConfig(USER_DIR . 'config'); + + return $list; + } +} diff --git a/system/src/Grav/Common/File/CompiledFile.php b/system/src/Grav/Common/File/CompiledFile.php new file mode 100644 index 000000000..907662b93 --- /dev/null +++ b/system/src/Grav/Common/File/CompiledFile.php @@ -0,0 +1,61 @@ +raw === null && $this->content === null) { + $key = md5($this->filename); + $file = Php::instance(CACHE_DIR . "/compiled/files/{$key}{$this->extension}.php"); + $modified = $this->modified(); + $class = get_class($this); + + if ($file->exists()) { + $cache = $file->exists() ? $file->content() : null; + } else { + $cache = null; + } + + + // Load real file if cache isn't up to date (or is invalid). + if ( + !is_array($cache) + || $cache['modified'] != $modified + || $cache['filename'] != $this->filename + || $cache['@class'] != $class + ) { + // Attempt to lock the file for writing. + $file->lock(false); + + // Decode RAW file into compiled array. + $data = $this->decode($this->raw()); + $cache = [ + '@class' => $class, + 'filename' => $this->filename, + 'modified' => $modified, + 'data' => $data + ]; + + // If compiled file wasn't already locked by another process, save it. + if ($file->locked() !== false) { + $file->save($cache); + $file->unlock(); + } + } + + $this->content = $cache['data']; + } + + return parent::content($var); + } +} diff --git a/system/src/Grav/Common/File/CompiledYaml.php b/system/src/Grav/Common/File/CompiledYaml.php new file mode 100644 index 000000000..1c5eca41d --- /dev/null +++ b/system/src/Grav/Common/File/CompiledYaml.php @@ -0,0 +1,9 @@ +register(new StreamsServiceProvider); + $container->register(new ConfigServiceProvider); return $container; } @@ -115,8 +114,8 @@ class Grav extends Container // Use output buffering to prevent headers from being sent too early. ob_start(); - // Initialize stream wrappers. - $this['locator']; + // Initialize configuration. + $this['config']->init(); $this['plugins']->init(); diff --git a/system/src/Grav/Common/Page/Medium.php b/system/src/Grav/Common/Page/Medium.php index 7cd97ccb6..39d15d13c 100644 --- a/system/src/Grav/Common/Page/Medium.php +++ b/system/src/Grav/Common/Page/Medium.php @@ -2,11 +2,11 @@ namespace Grav\Common\Page; use Grav\Common\Config; -use Grav\Common\Data\Blueprint; -use Grav\Common\Data\Data; -use Grav\Common\Filesystem\File\Yaml; use Grav\Common\Grav; use Grav\Common\GravTrait; +use Grav\Component\Data\Blueprint; +use Grav\Component\Data\Data; +use Grav\Component\Filesystem\File\Yaml; use Gregwar\Image\Image as ImageFile; /** diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index 21472ac1b..d44f5d47b 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -6,12 +6,12 @@ use Grav\Common\GravTrait; use Grav\Common\Utils; use Grav\Common\Cache; use Grav\Common\Twig; -use Grav\Common\Filesystem\File; -use Grav\Common\Filesystem\Folder; -use Grav\Common\Data; use Grav\Common\Uri; use Grav\Common\Grav; use Grav\Common\Taxonomy; +use Grav\Component\Data\Blueprint; +use Grav\Component\Filesystem\File; +use Grav\Component\Filesystem\Folder; use Grav\Component\EventDispatcher\Event; use Symfony\Component\Yaml\Yaml; @@ -463,7 +463,7 @@ class Page /** * Get blueprints for the page. * - * @return Data\Blueprint + * @return Blueprint */ public function blueprints() { diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php index f87bd8aee..447ccbc28 100644 --- a/system/src/Grav/Common/Page/Pages.php +++ b/system/src/Grav/Common/Page/Pages.php @@ -1,13 +1,14 @@ blueprints)) { - $this->blueprints = new Data\Blueprints('theme://blueprints/'); + $this->blueprints = new Blueprints('theme://blueprints/'); } try { @@ -311,7 +312,7 @@ class Pages */ static public function types() { - $blueprints = new Data\Blueprints('theme://blueprints/'); + $blueprints = new Blueprints('theme://blueprints/'); return $blueprints->types(); } diff --git a/system/src/Grav/Common/Plugin.php b/system/src/Grav/Common/Plugin.php index 0371cd41a..f0ac0ecad 100644 --- a/system/src/Grav/Common/Plugin.php +++ b/system/src/Grav/Common/Plugin.php @@ -1,6 +1,7 @@ get('blueprints'); $blueprint->name = $name; // Load default configuration. $file = File\Yaml::instance("plugin://{$name}/{$name}.yaml"); - $obj = new Data\Data($file->content(), $blueprint); + $obj = new Data($file->content(), $blueprint); // Override with user configuration. $file = File\Yaml::instance("user://config/plugins/{$name}.yaml"); diff --git a/system/src/Grav/Common/Service/ConfigServiceProvider.php b/system/src/Grav/Common/Service/ConfigServiceProvider.php new file mode 100644 index 000000000..c8183c705 --- /dev/null +++ b/system/src/Grav/Common/Service/ConfigServiceProvider.php @@ -0,0 +1,51 @@ +loadMasterBlueprints($c); + }; + + $container['config'] = function ($c) use ($self) { + return $self->loadMasterConfig($c); + }; + } + + public function loadMasterConfig(Container $container) + { + $file = CACHE_DIR . 'compiled/config/master.php'; + $data = is_file($file) ? (array) include $file : []; + + if (!$data) { + $file = GRAV_ROOT . '/config.php'; + $data = is_file($file) ? (array) include $file : []; + } + + return new Config($data, $container); + } + + public function loadMasterBlueprints(Container $container) + { + $file = CACHE_DIR . 'compiled/blueprints/master.php'; + $data = is_file($file) ? (array) include $file : []; + + return new Blueprints($data, $container); + } +} diff --git a/system/src/Grav/Common/Theme.php b/system/src/Grav/Common/Theme.php index 407dee282..3291e93c4 100644 --- a/system/src/Grav/Common/Theme.php +++ b/system/src/Grav/Common/Theme.php @@ -1,7 +1,8 @@ name}/{$this->name}.yaml")->content(); - - $this->config->merge(['themes' => [$this->name => $themeConfig]]); + $this->loadConfiguration(); /** @var ResourceLocator $locator */ $locator = $this->grav['locator']; @@ -61,4 +60,11 @@ class Theme extends Plugin } } + + protected function loadConfiguration() + { + $themeConfig = Yaml::instance(THEMES_DIR . "{$this->name}/{$this->name}.yaml")->content(); + + $this->config->merge(['themes' => [$this->name => $themeConfig]]); + } } diff --git a/system/src/Grav/Common/Themes.php b/system/src/Grav/Common/Themes.php index 7827afbda..a86aad8c5 100644 --- a/system/src/Grav/Common/Themes.php +++ b/system/src/Grav/Common/Themes.php @@ -1,7 +1,9 @@ get('blueprints'); $blueprint->name = $name; @@ -72,7 +74,7 @@ class Themes // Load default configuration. $file = File\Yaml::instance("theme://{$name}.yaml"); - $obj = new Data\Data($file->content(), $blueprint); + $obj = new Data($file->content(), $blueprint); // Override with user configuration. $file = File\Yaml::instance("user://config/themes/{$name}.yaml"); @@ -86,28 +88,32 @@ class Themes public function load($name = null) { + $grav = $this->grav; /** @var Config $config */ - $config = $this->grav['config']; + $config = $grav['config']; if (!$name) { $name = $config->get('system.pages.theme'); } - $file = THEMES_DIR . "{$name}/{$name}.php"; + $path = THEMES_DIR . $name; + $file = "{$path}/{$name}.php"; + if (file_exists($file)) { - $class = require_once $file; + // Local variables available in the file: $grav, $config, $name, $path, $file + $class = include $file; if (!is_object($class)) { $className = '\\Grav\\Theme\\' . ucfirst($name); if (class_exists($className)) { - $class = new $className($this->grav, $config, $name); + $class = new $className($grav, $config, $name); } } } if (empty($class)) { - $class = new Theme($this->grav, $config, $name); + $class = new Theme($grav, $config, $name); } return $class; diff --git a/system/src/Grav/Common/User/User.php b/system/src/Grav/Common/User/User.php index 678085c13..b95741cf9 100644 --- a/system/src/Grav/Common/User/User.php +++ b/system/src/Grav/Common/User/User.php @@ -1,7 +1,7 @@ items); + return Yaml::dump($this->toArray()); } /** - * Convert blueprints into JSON string. + * Convert object into JSON string. * * @return string */ public function toJson() { - return json_encode($this->items); + return json_encode($this->toArray()); } } diff --git a/system/src/Grav/Component/Blueprints/Blueprints.php b/system/src/Grav/Component/Blueprints/Blueprints.php new file mode 100644 index 000000000..03dc67aff --- /dev/null +++ b/system/src/Grav/Component/Blueprints/Blueprints.php @@ -0,0 +1,296 @@ + 1]; + + public function __construct(array $serialized = null) { + if ($serialized) { + $this->items = $serialized['items']; + $this->rules = $serialized['rules']; + $this->nested = $serialized['nested']; + $this->filter = $serialized['filter']; + } + } + + /** + * Set filter for inherited properties. + * + * @param array $filter List of field names to be inherited. + */ + public function setFilter(array $filter) + { + $this->filter = array_flip($filter); + } + + /** + * Get value by using dot notation for nested arrays/objects. + * + * @example $value = $data->get('this.is.my.nested.variable'); + * + * @param string $name Dot separated path to the requested value. + * @param mixed $default Default value (or null). + * @param string $separator Separator, defaults to '.' + * + * @return mixed Value. + */ + public function get($name, $default = null, $separator = '.') + { + $name = $separator != '.' ? strtr($name, $separator, '.') : $name; + + return isset($this->items[$name]) ? $this->items[$name] : $default; + } + + /** + * Set value by using dot notation for nested arrays/objects. + * + * @example $value = $data->set('this.is.my.nested.variable', $newField); + * + * @param string $name Dot separated path to the requested value. + * @param mixed $value New value. + * @param string $separator Separator, defaults to '.' + */ + public function set($name, $value, $separator = '.') + { + $name = $separator != '.' ? strtr($name, $separator, '.') : $name; + + $this->items[$name] = $value; + $this->addProperty($name); + } + + /** + * Define value by using dot notation for nested arrays/objects. + * + * @example $value = $data->set('this.is.my.nested.variable', true); + * + * @param string $name Dot separated path to the requested value. + * @param mixed $value New value. + * @param string $separator Separator, defaults to '.' + */ + public function def($name, $value, $separator = '.') + { + $this->set($name, $this->get($name, $value, $separator), $separator); + } + + /** + * Convert object into an array. + * + * @return array + */ + public function toArray() + { + return ['items' => $this->items, 'rules' => $this->rules, 'nested' => $this->nested, 'filter' => $this->filter]; + } + + /** + * Embed an array to the blueprint. + * + * @param $name + * @param array $value + * @param string $separator + */ + public function embed($name, array $value, $separator = '.') + { + if (isset($value['rules'])) { + $this->rules = array_merge($this->rules, $value['rules']); + } + if (!isset($value['form']['fields']) || !is_array($value['form']['fields'])) { + return; + } + $prefix = $name ? ($separator != '.' ? strtr($name, $separator, '.') : $name) . '.' : ''; + $params = array_intersect_key($this->filter, $value); + $this->parseFormFields($value['form']['fields'], $params, $prefix); + } + + /** + * Merge two arrays by using blueprints. + * + * @param array $data1 + * @param array $data2 + * @param string $name Optional + * @param string $separator Optional + * @return array + */ + public function mergeData(array $data1, array $data2, $name = null, $separator = '.') + { + $nested = $this->getProperty($name, $separator); + return $this->mergeArrays($data1, $data2, $nested); + } + + /** + * @param array $data1 + * @param array $data2 + * @param array $rules + * @return array + * @internal + */ + protected function mergeArrays(array $data1, array $data2, array $rules) + { + foreach ($data2 as $key => $field) { + $val = isset($rules[$key]) ? $rules[$key] : null; + $rule = is_string($val) ? $this->items[$val] : null; + + if (!$rule && array_key_exists($key, $data1) && is_array($field) && is_array($val)) { + // Array has been defined in blueprints. + $data1[$key] = $this->mergeArrays($data1[$key], $field, $val); + } else { + // Otherwise just take value from the data2. + $data1[$key] = $field; + } + } + + return $data1; + } + + /** + * Gets all field definitions from the blueprints. + * + * @param array $fields + * @param array $params + * @param string $prefix + * @internal + */ + protected function parseFormFields(array &$fields, $params, $prefix) + { + // Go though all the fields in current level. + foreach ($fields as $key => &$field) { + // Set name from the array key. + $field['name'] = $prefix . $key; + $field += $params; + + if (isset($field['fields'])) { + // Recursively get all the nested fields. + $newParams = array_intersect_key($this->filter, $field); + $this->parseFormFields($field['fields'], $newParams, $prefix); + } else { + // Add rule. + $this->items[$prefix . $key] = &$field; + $this->addProperty($prefix . $key); + + foreach ($field as $name => $value) { + // TODO: Support nested blueprints. + /* + if (isset($this->context) && $name == '@import') { + $values = (array) $value; + if (!isset($field['fields'])) { + $field['fields'] = array(); + } + foreach ($values as $bname) { + $b = $this->context->get($bname); + $field['fields'] = array_merge($field['fields'], $b->fields()); + } + } + + // Support for callable data values. + else + */ + if (substr($name, 0, 6) == '@data-') { + $property = substr($name, 6); + if (is_array($value)) { + $func = array_shift($value); + } else { + $func = $value; + $value = array(); + } + list($o, $f) = preg_split('/::/', $func); + if (!$f && function_exists($o)) { + $data = call_user_func_array($o, $value); + } elseif ($f && method_exists($o, $f)) { + $data = call_user_func_array(array($o, $f), $value); + } + + // If function returns a value, + if (isset($data)) { + if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) { + // Combine field and @data-field together. + $field[$property] += $data; + } else { + // Or create/replace field with @data-field. + $field[$property] = $data; + } + } + } + } + + // Initialize predefined validation rule. + if (isset($field['validate']['rule'])) { + $field['validate'] += $this->getRule($field['validate']['rule']); + } + } + } + } + + /** + * Get property from the definition. + * + * @param string $path Comma separated path to the property. + * @param string $separator + * @return array + * @internal + */ + protected function getProperty($path = null, $separator = '.') + { + if (!$path) { + return $this->nested; + } + $parts = explode($separator, $path); + $item = array_pop($parts); + + $nested = $this->nested; + foreach ($parts as $part) { + if (!isset($nested[$part])) { + return []; + } + $nested = $nested[$part]; + } + + return isset($nested[$item]) ? $nested[$item] : []; + } + + /** + * Add property to the definition. + * + * @param string $path Comma separated path to the property. + * @internal + */ + protected function addProperty($path) + { + $parts = explode('.', $path); + $item = array_pop($parts); + + $nested = &$this->nested; + foreach ($parts as $part) { + if (!isset($nested[$part])) { + $nested[$part] = array(); + } + $nested = &$nested[$part]; + } + + if (!isset($nested[$item])) { + $nested[$item] = $path; + } + } + + /** + * @param $rule + * @return array + * @internal + */ + protected function getRule($rule) + { + if (isset($this->rules[$rule]) && is_array($this->rules[$rule])) { + return $this->rules[$rule]; + } + return array(); + } +} diff --git a/system/src/Grav/Common/Data/Blueprint.php b/system/src/Grav/Component/Data/Blueprint.php similarity index 87% rename from system/src/Grav/Common/Data/Blueprint.php rename to system/src/Grav/Component/Data/Blueprint.php index 25fa6d1b0..37865c46a 100644 --- a/system/src/Grav/Common/Data/Blueprint.php +++ b/system/src/Grav/Component/Data/Blueprint.php @@ -1,5 +1,5 @@ 1]; /** * @param string $name * @param array $data * @param Blueprints $context */ - public function __construct($name, array $data, Blueprints $context) + public function __construct($name, array $data = array(), Blueprints $context = null) { $this->name = $name; $this->items = $data; $this->context = $context; } + /** + * Set filter for inherited properties. + * + * @param array $filter List of field names to be inherited. + */ + public function setFilter(array $filter) + { + $this->filter = array_flip($filter); + } + /** * Get value by using dot notation for nested arrays/objects. * @@ -103,8 +113,7 @@ class Blueprint public function fields() { if (!isset($this->fields)) { - $this->fields = isset($this->items['form']['fields']) ? $this->items['form']['fields'] : array(); - $this->getFields($this->fields); + $this->embed('', $this->items); } return $this->fields; @@ -135,7 +144,7 @@ class Blueprint * @param array $data2 * @return array */ - public function mergeData(array $data1, array $data2) + public function mergeData(array $data1, array $data2, $name = null) { // Initialize data $this->fields(); @@ -204,6 +213,35 @@ class Blueprint $this->items = $blueprints; } + /** + * Convert object into an array. + * + * @return array + */ + public function getState() + { + return ['name' => $this->name, 'items' => $this->items, 'rules' => $this->rules, 'nested' => $this->nested]; + } + + /** + * Embed an array to the blueprint. + * + * @param $name + * @param array $value + * @param string $separator + */ + public function embed($name, array $value, $separator = '.') + { + + if (!isset($value['form']['fields']) || !is_array($value['form']['fields'])) { + return; + } + // Initialize data + $this->fields(); + $prefix = $name ? strtr($name, $separator, '.') . '.' : ''; + $params = array_intersect_key($this->filter, $value); + $this->parseFormFields($value['form']['fields'], $params, $prefix); + } /** * @param array $data @@ -319,26 +357,30 @@ class Blueprint * Gets all field definitions from the blueprints. * * @param array $fields + * @param array $params + * @param string $prefix * @internal */ - protected function getFields(array &$fields) + protected function parseFormFields(array &$fields, $params, $prefix) { // Go though all the fields in current level. foreach ($fields as $key => &$field) { // Set name from the array key. - $field['name'] = $key; + $field['name'] = $prefix . $key; + $field += $params; if (isset($field['fields'])) { // Recursively get all the nested fields. - $this->getFields($field['fields']); + $newParams = array_intersect_key($this->filter, $field); + $this->parseFormFields($field['fields'], $newParams, $prefix); } else { // Add rule. - $this->rules[$key] = &$field; - $this->addProperty($key); + $this->rules[$prefix . $key] = &$field; + $this->addProperty($prefix . $key); foreach ($field as $name => $value) { // Support nested blueprints. - if ($name == '@import') { + if ($this->context && $name == '@import') { $values = (array) $value; if (!isset($field['fields'])) { $field['fields'] = array(); diff --git a/system/src/Grav/Common/Data/Blueprints.php b/system/src/Grav/Component/Data/Blueprints.php similarity index 98% rename from system/src/Grav/Common/Data/Blueprints.php rename to system/src/Grav/Component/Data/Blueprints.php index a247741ae..1ebff1c3c 100644 --- a/system/src/Grav/Common/Data/Blueprints.php +++ b/system/src/Grav/Component/Data/Blueprints.php @@ -1,5 +1,5 @@ set($name, $this->get($name, $default, $separator), $separator); } + /** + * Join two values together by using blueprints if available. + * + * @example $data->def('this.is.my.nested.variable', 'default'); + * + * @param string $name Dot separated path to the requested value. + * @param mixed $value Value to be joined. + * @param string $separator Separator, defaults to '.' + */ + public function join($name, $value, $separator = '.') + { + $old = $this->get($name, null, $separator); + if ($old === null) { + // Variable does not exist yet: just use the incoming value. + } elseif ($this->blueprints) { + // Blueprints: join values by using blueprints. + $value = $this->blueprints->mergeData($old, $value, $name, $separator); + } else { + // No blueprints: replace existing top level variables with the new ones. + $value =array_merge($old, $value); + } + + $this->set($name, $value, $separator); + } + /** * Merge two sets of data together. * diff --git a/system/src/Grav/Common/Data/DataInterface.php b/system/src/Grav/Component/Data/DataInterface.php similarity index 92% rename from system/src/Grav/Common/Data/DataInterface.php rename to system/src/Grav/Component/Data/DataInterface.php index 7ce6ec518..3959be84e 100644 --- a/system/src/Grav/Common/Data/DataInterface.php +++ b/system/src/Grav/Component/Data/DataInterface.php @@ -1,8 +1,8 @@ toArray(); - - foreach ($options as $k => $v) { - if (is_int($v)) { - $vars[] = "\tpublic $" . $k . " = " . $v . ";"; - } elseif (is_bool($v)) { - $vars[] = "\tpublic $" . $k . " = " . ($v ? 'true' : 'false') . ";"; - } elseif (is_scalar($v)) { - $vars[] = "\tpublic $" . $k . " = '" . addcslashes($v, '\\\'') . "';"; - } elseif (is_array($v) || is_object($v)) { - $vars[] = "\tpublic $" . $k . " = " . $this->encodeArray((array) $v) . ";"; - } - } - $vars = implode("\n", $vars); - - return "encodeArray((array) $var)};\n"; } /** @@ -96,12 +76,12 @@ class Config extends General * * @return array */ - protected function encodeArray($a, $level = 1) + protected function encodeArray(array $a, $level = 0) { - $r = array(); + $r = []; foreach ($a as $k => $v) { if (is_array($v) || is_object($v)) { - $r[] = '"' . $k . '" => ' . $this->encodeArray((array) $v, $level+1); + $r[] = "'" . $k . "' => " . $this->encodeArray((array) $v, $level + 1); } elseif (is_int($v)) { $r[] = "'" . $k . "' => " . $v; } elseif (is_bool($v)) { @@ -111,19 +91,19 @@ class Config extends General } } - $tabs = str_repeat("\t", $level); - return "array(\n\t{$tabs}" . implode(",\n\t{$tabs}", $r) . "\n{$tabs})"; + $space = str_repeat(" ", $level); + return "[\n {$space}" . implode(",\n {$space}", $r) . "\n{$space}]"; } /** - * Decode RAW string into contents. + * Decode PHP file into contents. * * @param string $var - * @return \Grav\Common\Config + * @return array */ protected function decode($var) { - // TODO: improve this one later, works only for single file... - return class_exists('\Grav\Config') ? new \Grav\Config($this->filename) : new Config($this->filename); + $var = (array) include $this->filename; + return $var; } } diff --git a/system/src/Grav/Common/Filesystem/File/Yaml.php b/system/src/Grav/Component/Filesystem/File/Yaml.php similarity index 92% rename from system/src/Grav/Common/Filesystem/File/Yaml.php rename to system/src/Grav/Component/Filesystem/File/Yaml.php index e93e0e03e..6fd42da32 100644 --- a/system/src/Grav/Common/Filesystem/File/Yaml.php +++ b/system/src/Grav/Component/Filesystem/File/Yaml.php @@ -1,5 +1,5 @@ extension = YAML_EXT; + $this->extension = '.yaml'; } /** diff --git a/system/src/Grav/Common/Filesystem/FileInterface.php b/system/src/Grav/Component/Filesystem/FileInterface.php similarity index 98% rename from system/src/Grav/Common/Filesystem/FileInterface.php rename to system/src/Grav/Component/Filesystem/FileInterface.php index a090e550c..83afb87f0 100644 --- a/system/src/Grav/Common/Filesystem/FileInterface.php +++ b/system/src/Grav/Component/Filesystem/FileInterface.php @@ -1,5 +1,5 @@ schemes[$scheme]); + + $this->cache = []; } /** @@ -66,14 +70,14 @@ class ResourceLocator } /** - * @param string $uri - * @param bool $absolute - * @param bool $array + * Parse resource. * + * @param $uri + * @return array * @throws \InvalidArgumentException - * @return array|string|bool + * @internal */ - protected function find($uri, $array, $absolute) + protected function parseResource($uri) { $segments = explode('://', $uri, 2); $file = array_pop($segments); @@ -90,6 +94,28 @@ class ResourceLocator throw new \InvalidArgumentException("Invalid resource {$scheme}://"); } + return [$file, $scheme]; + } + + /** + * @param string $uri + * @param bool $absolute + * @param bool $array + * + * @throws \InvalidArgumentException + * @return array|string|bool + * @internal + */ + protected function find($uri, $array, $absolute) + { + // Local caching: make sure that the function gets only called at once for each file. + $key = $uri .'@'. (int) $array . (int) $absolute; + if (isset($this->cache[$key])) { + return $this->cache[$key]; + } + + list ($file, $scheme) = $this->parseResource($uri); + $results = $array ? [] : false; foreach ($this->schemes[$scheme] as $prefix => $paths) { if ($prefix && strpos($file, $prefix) !== 0) { @@ -98,17 +124,19 @@ class ResourceLocator foreach ($paths as $path) { $filename = $path . '/' . ltrim(substr($file, strlen($prefix)), '\/'); - $lookup = ROOT_DIR . '/' . $filename; + $lookup = GRAV_ROOT . '/' . $filename; if (file_exists($lookup)) { if (!$array) { - return $absolute ? $lookup : $filename; + $results = $absolute ? $lookup : $filename; + break; } $results[] = $absolute ? $lookup : $filename; } } } + $this->cache[$key] = $results; return $results; } } diff --git a/system/src/Grav/Common/Session/Message.php b/system/src/Grav/Component/Session/Message.php similarity index 96% rename from system/src/Grav/Common/Session/Message.php rename to system/src/Grav/Component/Session/Message.php index 1039c527b..57a4c0d28 100644 --- a/system/src/Grav/Common/Session/Message.php +++ b/system/src/Grav/Component/Session/Message.php @@ -1,7 +1,5 @@ started = true; diff --git a/vendor/autoload.php b/vendor/autoload.php index d84c250d1..5aad5fccd 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderIniteef751e17db86fa31c0c46c61acf76f4::getLoader(); +return ComposerAutoloaderInit783fd05b00682a5818a5d9d5601c81fe::getLoader(); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index b6b38da50..2388679c0 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -28,21 +28,13 @@ return array( 'FirePHP' => $vendorDir . '/mrclay/minify/min/lib/FirePHP.php', 'Grav\\Common\\Assets' => $baseDir . '/system/src/Grav/Common/Assets.php', 'Grav\\Common\\Cache' => $baseDir . '/system/src/Grav/Common/Cache.php', - 'Grav\\Common\\Config' => $baseDir . '/system/src/Grav/Common/Config.php', - 'Grav\\Common\\Data\\Blueprint' => $baseDir . '/system/src/Grav/Common/Data/Blueprint.php', - 'Grav\\Common\\Data\\Blueprints' => $baseDir . '/system/src/Grav/Common/Data/Blueprints.php', - 'Grav\\Common\\Data\\Data' => $baseDir . '/system/src/Grav/Common/Data/Data.php', - 'Grav\\Common\\Data\\DataInterface' => $baseDir . '/system/src/Grav/Common/Data/DataInterface.php', - 'Grav\\Common\\Data\\Validation' => $baseDir . '/system/src/Grav/Common/Data/Validation.php', + 'Grav\\Common\\Config' => $baseDir . '/system/src/Grav/Common/ConfigBak.php', + 'Grav\\Common\\Config\\Blueprints' => $baseDir . '/system/src/Grav/Common/Config/Blueprints.php', + 'Grav\\Common\\Config\\Config' => $baseDir . '/system/src/Grav/Common/Config/Config.php', + 'Grav\\Common\\Config\\ConfigServiceProvider' => $baseDir . '/system/src/Grav/Common/Service/ConfigServiceProvider.php', 'Grav\\Common\\Debugger' => $baseDir . '/system/src/Grav/Common/Debugger.php', - 'Grav\\Common\\Filesystem\\FileInterface' => $baseDir . '/system/src/Grav/Common/Filesystem/FileInterface.php', - 'Grav\\Common\\Filesystem\\File\\Config' => $baseDir . '/system/src/Grav/Common/Filesystem/File/Config.php', - 'Grav\\Common\\Filesystem\\File\\General' => $baseDir . '/system/src/Grav/Common/Filesystem/File/General.php', - 'Grav\\Common\\Filesystem\\File\\Json' => $baseDir . '/system/src/Grav/Common/Filesystem/File/Json.php', - 'Grav\\Common\\Filesystem\\File\\Log' => $baseDir . '/system/src/Grav/Common/Filesystem/File/Log.php', - 'Grav\\Common\\Filesystem\\File\\Markdown' => $baseDir . '/system/src/Grav/Common/Filesystem/File/Markdown.php', - 'Grav\\Common\\Filesystem\\File\\Yaml' => $baseDir . '/system/src/Grav/Common/Filesystem/File/Yaml.php', - 'Grav\\Common\\Filesystem\\Folder' => $baseDir . '/system/src/Grav/Common/Filesystem/Folder.php', + 'Grav\\Common\\File\\CompiledFile' => $baseDir . '/system/src/Grav/Common/File/CompiledFile.php', + 'Grav\\Common\\File\\CompiledYaml' => $baseDir . '/system/src/Grav/Common/File/CompiledYaml.php', 'Grav\\Common\\Getters' => $baseDir . '/system/src/Grav/Common/Getters.php', 'Grav\\Common\\Grav' => $baseDir . '/system/src/Grav/Common/Grav.php', 'Grav\\Common\\GravTrait' => $baseDir . '/system/src/Grav/Common/GravTrait.php', @@ -57,8 +49,6 @@ return array( 'Grav\\Common\\Plugins' => $baseDir . '/system/src/Grav/Common/Plugins.php', 'Grav\\Common\\Registry' => $baseDir . '/system/src/Grav/Common/Registry.php', 'Grav\\Common\\Service\\StreamsServiceProvider' => $baseDir . '/system/src/Grav/Common/Service/StreamsServiceProvider.php', - 'Grav\\Common\\Session\\Message' => $baseDir . '/system/src/Grav/Common/Session/Message.php', - 'Grav\\Common\\Session\\Session' => $baseDir . '/system/src/Grav/Common/Session/Session.php', 'Grav\\Common\\Taxonomy' => $baseDir . '/system/src/Grav/Common/Taxonomy.php', 'Grav\\Common\\Theme' => $baseDir . '/system/src/Grav/Common/Theme.php', 'Grav\\Common\\Themes' => $baseDir . '/system/src/Grav/Common/Themes.php', @@ -69,18 +59,38 @@ return array( 'Grav\\Common\\User\\User' => $baseDir . '/system/src/Grav/Common/User/User.php', 'Grav\\Common\\Utils' => $baseDir . '/system/src/Grav/Common/Utils.php', 'Grav\\Component\\ArrayTraits\\ArrayAccess' => $baseDir . '/system/src/Grav/Component/ArrayTraits/ArrayAccess.php', + 'Grav\\Component\\ArrayTraits\\ArrayAccessWithGetters' => $baseDir . '/system/src/Grav/Component/ArrayTraits/ArrayAccessWithGetters.php', 'Grav\\Component\\ArrayTraits\\Constructor' => $baseDir . '/system/src/Grav/Component/ArrayTraits/Constructor.php', 'Grav\\Component\\ArrayTraits\\Countable' => $baseDir . '/system/src/Grav/Component/ArrayTraits/Countable.php', - 'Grav\\Component\\ArrayTraits\\Getters' => $baseDir . '/system/src/Grav/Component/ArrayTraits/Getters.php', + 'Grav\\Component\\ArrayTraits\\Export' => $baseDir . '/system/src/Grav/Component/ArrayTraits/Export.php', + 'Grav\\Component\\ArrayTraits\\Iterator' => $baseDir . '/system/src/Grav/Component/ArrayTraits/Iterator.php', + 'Grav\\Component\\ArrayTraits\\Serializable' => $baseDir . '/system/src/Grav/Component/ArrayTraits/Serializable.php', + 'Grav\\Component\\Blueprints\\Blueprints' => $baseDir . '/system/src/Grav/Component/Blueprints/Blueprints.php', + 'Grav\\Component\\Config\\ConfigLoader' => $baseDir . '/system/src/Grav/Component/Config/ConfigLoader.php', 'Grav\\Component\\DI\\Container' => $baseDir . '/system/src/Grav/Component/DI/Container.php', 'Grav\\Component\\DI\\ServiceProviderInterface' => $baseDir . '/system/src/Grav/Component/DI/ServiceProviderInterface.php', + 'Grav\\Component\\Data\\Blueprint' => $baseDir . '/system/src/Grav/Component/Data/Blueprint.php', + 'Grav\\Component\\Data\\Blueprints' => $baseDir . '/system/src/Grav/Component/Data/Blueprints.php', + 'Grav\\Component\\Data\\Data' => $baseDir . '/system/src/Grav/Component/Data/Data.php', + 'Grav\\Component\\Data\\DataInterface' => $baseDir . '/system/src/Grav/Component/Data/DataInterface.php', + 'Grav\\Component\\Data\\Validation' => $baseDir . '/system/src/Grav/Component/Data/Validation.php', 'Grav\\Component\\EventDispatcher\\Event' => $baseDir . '/system/src/Grav/Component/EventDispatcher/Event.php', 'Grav\\Component\\EventDispatcher\\EventDispatcher' => $baseDir . '/system/src/Grav/Component/EventDispatcher/EventDispatcher.php', 'Grav\\Component\\EventDispatcher\\EventSubscriberInterface' => $baseDir . '/system/src/Grav/Component/EventDispatcher/EventSubscriberInterface.php', + 'Grav\\Component\\Filesystem\\FileInterface' => $baseDir . '/system/src/Grav/Component/Filesystem/FileInterface.php', + 'Grav\\Component\\Filesystem\\File\\General' => $baseDir . '/system/src/Grav/Component/Filesystem/File/General.php', + 'Grav\\Component\\Filesystem\\File\\Json' => $baseDir . '/system/src/Grav/Component/Filesystem/File/Json.php', + 'Grav\\Component\\Filesystem\\File\\Log' => $baseDir . '/system/src/Grav/Component/Filesystem/File/Log.php', + 'Grav\\Component\\Filesystem\\File\\Markdown' => $baseDir . '/system/src/Grav/Component/Filesystem/File/Markdown.php', + 'Grav\\Component\\Filesystem\\File\\Php' => $baseDir . '/system/src/Grav/Component/Filesystem/File/Php.php', + 'Grav\\Component\\Filesystem\\File\\Yaml' => $baseDir . '/system/src/Grav/Component/Filesystem/File/Yaml.php', + 'Grav\\Component\\Filesystem\\Folder' => $baseDir . '/system/src/Grav/Component/Filesystem/Folder.php', 'Grav\\Component\\Filesystem\\ResourceLocator' => $baseDir . '/system/src/Grav/Component/Filesystem/ResourceLocator.php', 'Grav\\Component\\Filesystem\\StreamWrapper\\ReadOnlyStream' => $baseDir . '/system/src/Grav/Component/Filesystem/StreamWrapper/ReadOnlyStream.php', 'Grav\\Component\\Filesystem\\StreamWrapper\\Stream' => $baseDir . '/system/src/Grav/Component/Filesystem/StreamWrapper/Stream.php', 'Grav\\Component\\Filesystem\\StreamWrapper\\StreamInterface' => $baseDir . '/system/src/Grav/Component/Filesystem/StreamWrapper/StreamInterface.php', + 'Grav\\Component\\Session\\Message' => $baseDir . '/system/src/Grav/Component/Session/Message.php', + 'Grav\\Component\\Session\\Session' => $baseDir . '/system/src/Grav/Component/Session/Session.php', 'Grav\\Console\\BackupCommand' => $baseDir . '/system/src/Grav/Console/BackupCommand.php', 'Grav\\Console\\CleanCommand' => $baseDir . '/system/src/Grav/Console/CleanCommand.php', 'Grav\\Console\\ClearCacheCommand' => $baseDir . '/system/src/Grav/Console/ClearCacheCommand.php', @@ -157,6 +167,31 @@ return array( 'Pimple\\Tests\\Fixtures\\NonInvokable' => $vendorDir . '/pimple/pimple/src/Pimple/Tests/Fixtures/NonInvokable.php', 'Pimple\\Tests\\Fixtures\\PimpleServiceProvider' => $vendorDir . '/pimple/pimple/src/Pimple/Tests/Fixtures/PimpleServiceProvider.php', 'Pimple\\Tests\\Fixtures\\Service' => $vendorDir . '/pimple/pimple/src/Pimple/Tests/Fixtures/Service.php', + 'RocketTheme\\Toolbox\\ArrayTraits\\ArrayAccess' => $vendorDir . '/rockettheme/toolbox/ArrayTraits/src/ArrayAccess.php', + 'RocketTheme\\Toolbox\\ArrayTraits\\ArrayAccessWithGetters' => $vendorDir . '/rockettheme/toolbox/ArrayTraits/src/ArrayAccessWithGetters.php', + 'RocketTheme\\Toolbox\\ArrayTraits\\Constructor' => $vendorDir . '/rockettheme/toolbox/ArrayTraits/src/Constructor.php', + 'RocketTheme\\Toolbox\\ArrayTraits\\Countable' => $vendorDir . '/rockettheme/toolbox/ArrayTraits/src/Countable.php', + 'RocketTheme\\Toolbox\\ArrayTraits\\Export' => $vendorDir . '/rockettheme/toolbox/ArrayTraits/src/Export.php', + 'RocketTheme\\Toolbox\\ArrayTraits\\ExportInterface' => $vendorDir . '/rockettheme/toolbox/ArrayTraits/src/ExportInterface.php', + 'RocketTheme\\Toolbox\\ArrayTraits\\Iterator' => $vendorDir . '/rockettheme/toolbox/ArrayTraits/src/Iterator.php', + 'RocketTheme\\Toolbox\\ArrayTraits\\Serializable' => $vendorDir . '/rockettheme/toolbox/ArrayTraits/src/Serializable.php', + 'RocketTheme\\Toolbox\\DI\\Container' => $vendorDir . '/rockettheme/toolbox/DI/src/Container.php', + 'RocketTheme\\Toolbox\\DI\\ServiceProviderInterface' => $vendorDir . '/rockettheme/toolbox/DI/src/ServiceProviderInterface.php', + 'RocketTheme\\Toolbox\\Event\\Event' => $vendorDir . '/rockettheme/toolbox/Event/src/Event.php', + 'RocketTheme\\Toolbox\\Event\\EventDispatcher' => $vendorDir . '/rockettheme/toolbox/Event/src/EventDispatcher.php', + 'RocketTheme\\Toolbox\\Event\\EventSubscriberInterface' => $vendorDir . '/rockettheme/toolbox/Event/src/EventSubscriberInterface.php', + 'RocketTheme\\Toolbox\\File\\File' => $vendorDir . '/rockettheme/toolbox/File/src/File.php', + 'RocketTheme\\Toolbox\\File\\FileInterface' => $vendorDir . '/rockettheme/toolbox/File/src/FileInterface.php', + 'RocketTheme\\Toolbox\\File\\JsonFile' => $vendorDir . '/rockettheme/toolbox/File/src/JsonFile.php', + 'RocketTheme\\Toolbox\\File\\LogFile' => $vendorDir . '/rockettheme/toolbox/File/src/LogFile.php', + 'RocketTheme\\Toolbox\\File\\MarkdownFile' => $vendorDir . '/rockettheme/toolbox/File/src/MarkdownFile.php', + 'RocketTheme\\Toolbox\\File\\PhpFile' => $vendorDir . '/rockettheme/toolbox/File/src/PhpFile.php', + 'RocketTheme\\Toolbox\\File\\YamlFile' => $vendorDir . '/rockettheme/toolbox/File/src/YamlFile.php', + 'RocketTheme\\Toolbox\\Session\\Message' => $vendorDir . '/rockettheme/toolbox/Session/src/Message.php', + 'RocketTheme\\Toolbox\\Session\\Session' => $vendorDir . '/rockettheme/toolbox/Session/src/Session.php', + 'RocketTheme\\Toolbox\\StreamWrapper\\ReadOnlyStream' => $vendorDir . '/rockettheme/toolbox/StreamWrapper/src/ReadOnlyStream.php', + 'RocketTheme\\Toolbox\\StreamWrapper\\Stream' => $vendorDir . '/rockettheme/toolbox/StreamWrapper/src/Stream.php', + 'RocketTheme\\Toolbox\\StreamWrapper\\StreamInterface' => $vendorDir . '/rockettheme/toolbox/StreamWrapper/src/StreamInterface.php', 'Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Symfony/Component/Console/Application.php', 'Symfony\\Component\\Console\\Command\\Command' => $vendorDir . '/symfony/console/Symfony/Component/Console/Command/Command.php', 'Symfony\\Component\\Console\\Command\\HelpCommand' => $vendorDir . '/symfony/console/Symfony/Component/Console/Command/HelpCommand.php', diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index 945cea325..63980c11d 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,9 +6,9 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + $vendorDir . '/ircmaxell/password-compat/lib/password.php', $vendorDir . '/ornicar/php-user-agent/lib/phpUserAgent.php', $vendorDir . '/ornicar/php-user-agent/lib/phpUserAgentStringParser.php', $vendorDir . '/tracy/tracy/src/shortcuts.php', - $vendorDir . '/ircmaxell/password-compat/lib/password.php', $baseDir . '/system/defines.php', ); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php index 2c705bd2a..fd0d17bdd 100644 --- a/vendor/composer/autoload_namespaces.php +++ b/vendor/composer/autoload_namespaces.php @@ -15,5 +15,6 @@ return array( 'Parsedown' => array($vendorDir . '/erusev/parsedown'), 'Gregwar\\Image' => array($vendorDir . '/gregwar/image'), 'Gregwar\\Cache' => array($vendorDir . '/gregwar/cache'), + 'Grav\\' => array($baseDir . '/system/src'), 'Doctrine\\Common\\Cache\\' => array($vendorDir . '/doctrine/cache/lib'), ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 687a12874..299285f93 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -6,5 +6,11 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( - 'Grav\\' => array($baseDir . '/system/src'), + 'RocketTheme\\Toolbox\\StreamWrapper\\' => array($vendorDir . '/rockettheme/toolbox/StreamWrapper/src'), + 'RocketTheme\\Toolbox\\Session\\' => array($vendorDir . '/rockettheme/toolbox/Session/src'), + 'RocketTheme\\Toolbox\\ResourceLocation\\' => array($vendorDir . '/rockettheme/toolbox/ResourceLocation/src'), + 'RocketTheme\\Toolbox\\File\\' => array($vendorDir . '/rockettheme/toolbox/File/src'), + 'RocketTheme\\Toolbox\\Event\\' => array($vendorDir . '/rockettheme/toolbox/Event/src'), + 'RocketTheme\\Toolbox\\DI\\' => array($vendorDir . '/rockettheme/toolbox/DI/src'), + 'RocketTheme\\Toolbox\\ArrayTraits\\' => array($vendorDir . '/rockettheme/toolbox/ArrayTraits/src'), ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 733b9e1e2..f6c203c91 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderIniteef751e17db86fa31c0c46c61acf76f4 +class ComposerAutoloaderInit783fd05b00682a5818a5d9d5601c81fe { private static $loader; @@ -19,9 +19,9 @@ class ComposerAutoloaderIniteef751e17db86fa31c0c46c61acf76f4 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderIniteef751e17db86fa31c0c46c61acf76f4', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit783fd05b00682a5818a5d9d5601c81fe', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderIniteef751e17db86fa31c0c46c61acf76f4', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit783fd05b00682a5818a5d9d5601c81fe', 'loadClassLoader')); $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -42,14 +42,14 @@ class ComposerAutoloaderIniteef751e17db86fa31c0c46c61acf76f4 $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $file) { - composerRequireeef751e17db86fa31c0c46c61acf76f4($file); + composerRequire783fd05b00682a5818a5d9d5601c81fe($file); } return $loader; } } -function composerRequireeef751e17db86fa31c0c46c61acf76f4($file) +function composerRequire783fd05b00682a5818a5d9d5601c81fe($file) { require $file; } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 863259012..76077e37c 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -99,52 +99,6 @@ "parser" ] }, - { - "name": "erusev/parsedown-extra", - "version": "0.2.0", - "version_normalized": "0.2.0.0", - "source": { - "type": "git", - "url": "https://github.com/erusev/parsedown-extra.git", - "reference": "7578fe28ce42e7a1fff4ba2aada3807c4c03d04b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/7578fe28ce42e7a1fff4ba2aada3807c4c03d04b", - "reference": "7578fe28ce42e7a1fff4ba2aada3807c4c03d04b", - "shasum": "" - }, - "require": { - "erusev/parsedown": "~1.0" - }, - "time": "2014-08-16 11:20:35", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-0": { - "ParsedownExtra": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Emanuil Rusev", - "email": "hello@erusev.com", - "homepage": "http://erusev.com" - } - ], - "description": "An extension of Parsedown that adds support for Markdown Extra.", - "homepage": "https://github.com/erusev/parsedown-extra", - "keywords": [ - "markdown", - "markdown extra", - "parsedown", - "parser" - ] - }, { "name": "doctrine/cache", "version": "v1.3.0", @@ -518,62 +472,6 @@ "description": "Symfony EventDispatcher Component", "homepage": "http://symfony.com" }, - { - "name": "tracy/tracy", - "version": "v2.2.2", - "version_normalized": "2.2.2.0", - "source": { - "type": "git", - "url": "https://github.com/nette/tracy.git", - "reference": "f5a2647c9d0174d218d626eab3952ea3a523c6e7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/tracy/zipball/f5a2647c9d0174d218d626eab3952ea3a523c6e7", - "reference": "f5a2647c9d0174d218d626eab3952ea3a523c6e7", - "shasum": "" - }, - "require": { - "php": ">=5.3.1" - }, - "require-dev": { - "nette/tester": "~1.0" - }, - "time": "2014-06-24 01:18:03", - "type": "library", - "installation-source": "dist", - "autoload": { - "classmap": [ - "src/Tracy" - ], - "files": [ - "src/shortcuts.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "http://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "http://nette.org/contributors" - } - ], - "description": "Tracy: useful PHP debugger", - "homepage": "http://tracy.nette.org", - "keywords": [ - "debug", - "debugger", - "nette" - ] - }, { "name": "gregwar/cache", "version": "v1.0.7", @@ -704,5 +602,160 @@ "hashing", "password" ] + }, + { + "name": "erusev/parsedown-extra", + "version": "0.2.1", + "version_normalized": "0.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown-extra.git", + "reference": "424e63fef5299f2a5a0464cd22a666b7a7b48657" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/424e63fef5299f2a5a0464cd22a666b7a7b48657", + "reference": "424e63fef5299f2a5a0464cd22a666b7a7b48657", + "shasum": "" + }, + "require": { + "erusev/parsedown": "~1.0" + }, + "time": "2014-08-25 10:49:57", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "ParsedownExtra": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "An extension of Parsedown that adds support for Markdown Extra.", + "homepage": "https://github.com/erusev/parsedown-extra", + "keywords": [ + "markdown", + "markdown extra", + "parsedown", + "parser" + ] + }, + { + "name": "tracy/tracy", + "version": "v2.2.3", + "version_normalized": "2.2.3.0", + "source": { + "type": "git", + "url": "https://github.com/nette/tracy.git", + "reference": "97889d2b8cfb7607cc370ca0ddb97c6f5b43deb9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/tracy/zipball/97889d2b8cfb7607cc370ca0ddb97c6f5b43deb9", + "reference": "97889d2b8cfb7607cc370ca0ddb97c6f5b43deb9", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "nette/tester": "~1.0" + }, + "time": "2014-08-24 23:36:30", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "src/Tracy" + ], + "files": [ + "src/shortcuts.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "http://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "http://nette.org/contributors" + } + ], + "description": "Tracy: useful PHP debugger", + "homepage": "http://tracy.nette.org", + "keywords": [ + "debug", + "debugger", + "nette" + ] + }, + { + "name": "rockettheme/toolbox", + "version": "dev-develop", + "version_normalized": "dev-develop", + "source": { + "type": "git", + "url": "https://github.com/rockettheme/toolbox.git", + "reference": "5f26caed7527e1b30ac9f8200af79017c109a79c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/5f26caed7527e1b30ac9f8200af79017c109a79c", + "reference": "5f26caed7527e1b30ac9f8200af79017c109a79c", + "shasum": "" + }, + "require": { + "ircmaxell/password-compat": "1.0.*", + "php": ">=5.4.0", + "pimple/pimple": "~3.0", + "symfony/event-dispatcher": "~2.5", + "symfony/yaml": "~2.5" + }, + "require-dev": { + "phpunit/phpunit": "4.0.*" + }, + "time": "2014-08-28 14:25:14", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-4": { + "RocketTheme\\Toolbox\\ArrayTraits\\": "ArrayTraits/src", + "RocketTheme\\Toolbox\\DI\\": "DI/src", + "RocketTheme\\Toolbox\\Event\\": "Event/src", + "RocketTheme\\Toolbox\\File\\": "File/src", + "RocketTheme\\Toolbox\\ResourceLocation\\": "ResourceLocation/src", + "RocketTheme\\Toolbox\\Session\\": "Session/src", + "RocketTheme\\Toolbox\\StreamWrapper\\": "StreamWrapper/src" + } + }, + "license": [ + "MIT" + ], + "description": "RocketTheme Toolbox Library", + "homepage": "http://www.rockettheme.com", + "keywords": [ + "php", + "rockettheme" + ], + "support": { + "source": "https://github.com/rockettheme/toolbox/tree/develop", + "issues": "https://github.com/rockettheme/toolbox/issues" + } } ] diff --git a/vendor/erusev/parsedown-extra/ParsedownExtra.php b/vendor/erusev/parsedown-extra/ParsedownExtra.php index b6ac978dc..ef6c6ee2e 100644 --- a/vendor/erusev/parsedown-extra/ParsedownExtra.php +++ b/vendor/erusev/parsedown-extra/ParsedownExtra.php @@ -166,7 +166,12 @@ class ParsedownExtra extends Parsedown { $DOMDocument = new DOMDocument; - $DOMDocument->loadXML($Block['element']); + $DOMDocument->loadXML($Block['element'], LIBXML_NOERROR | LIBXML_NOWARNING); + + if ($DOMDocument->documentElement === null) + { + return $Block; + } $result = $DOMDocument->documentElement->getAttribute('markdown'); diff --git a/vendor/tracy/tracy/src/Tracy/Debugger.php b/vendor/tracy/tracy/src/Tracy/Debugger.php index b91016871..fc6247eeb 100644 --- a/vendor/tracy/tracy/src/Tracy/Debugger.php +++ b/vendor/tracy/tracy/src/Tracy/Debugger.php @@ -103,6 +103,9 @@ class Debugger /** @var string name of the directory where errors should be logged */ public static $logDirectory; + /** @var int log bluescreen in production mode for this error severity */ + public static $logSeverity = 0; + /** @var string|array email(s) to which send error notifications */ public static $email; @@ -475,6 +478,12 @@ class Debugger } elseif (($severity & error_reporting()) !== $severity) { return FALSE; // calls normal error handler to fill-in error_get_last() + } elseif (($severity & self::$logSeverity) === $severity) { + $e = new ErrorException($message, 0, $severity, $file, $line); + $e->context = $context; + self::log($e, self::ERROR); + return NULL; + } elseif (!self::$productionMode && (is_bool(self::$strictMode) ? self::$strictMode : ((self::$strictMode & $severity) === $severity))) { $e = new ErrorException($message, 0, $severity, $file, $line); $e->context = $context; diff --git a/vendor/tracy/tracy/src/Tracy/Helpers.php b/vendor/tracy/tracy/src/Tracy/Helpers.php index 56f24e563..851098b1e 100644 --- a/vendor/tracy/tracy/src/Tracy/Helpers.php +++ b/vendor/tracy/tracy/src/Tracy/Helpers.php @@ -79,6 +79,7 @@ class Helpers } + /** @internal */ public static function fixStack($exception) { if (function_exists('xdebug_get_function_stack')) { @@ -104,11 +105,7 @@ class Helpers } - /** - * Returns correctly UTF-8 encoded string. - * @param string byte stream to fix - * @return string - */ + /** @internal */ public static function fixEncoding($s) { if (PHP_VERSION_ID < 50400) { diff --git a/vendor/tracy/tracy/src/Tracy/Logger.php b/vendor/tracy/tracy/src/Tracy/Logger.php index 89f29276b..767342cd1 100644 --- a/vendor/tracy/tracy/src/Tracy/Logger.php +++ b/vendor/tracy/tracy/src/Tracy/Logger.php @@ -72,6 +72,7 @@ class Logger * @param string * @param string * @return void + * @internal */ public static function defaultMailer($message, $email) { diff --git a/vendor/tracy/tracy/src/Tracy/OutputDebugger.php b/vendor/tracy/tracy/src/Tracy/OutputDebugger.php index f47abe94b..011a0ec46 100644 --- a/vendor/tracy/tracy/src/Tracy/OutputDebugger.php +++ b/vendor/tracy/tracy/src/Tracy/OutputDebugger.php @@ -42,6 +42,7 @@ class OutputDebugger } + /** @internal */ public function handler($s, $phase) { $trace = debug_backtrace(FALSE); @@ -62,7 +63,6 @@ class OutputDebugger { $res = ''; foreach ($this->list as $item) { - list($file, $line, $s) = $item; $res .= Helpers::editorLink($item[0], $item[1]) . ' ' . str_replace(self::BOM, 'BOM', Dumper::toHtml($item[2])) . "
\n"; } diff --git a/vendor/tracy/tracy/src/Tracy/templates/bluescreen.css b/vendor/tracy/tracy/src/Tracy/templates/bluescreen.css index b41f3d777..d3da27558 100644 --- a/vendor/tracy/tracy/src/Tracy/templates/bluescreen.css +++ b/vendor/tracy/tracy/src/Tracy/templates/bluescreen.css @@ -14,6 +14,7 @@ html { background: white; color: #333; position: absolute; + z-index: 20000; left: 0; top: 0; width: 100%; @@ -54,7 +55,6 @@ html { position: absolute; right: .5em; top: .5em; - z-index: 20000; text-decoration: none; background: #CD1818; color: white !important; diff --git a/vendor/tracy/tracy/src/Tracy/templates/bluescreen.phtml b/vendor/tracy/tracy/src/Tracy/templates/bluescreen.phtml index 9e76c66bd..94729c6fc 100644 --- a/vendor/tracy/tracy/src/Tracy/templates/bluescreen.phtml +++ b/vendor/tracy/tracy/src/Tracy/templates/bluescreen.phtml @@ -117,7 +117,7 @@ $counter = 0; inner-code - " class="tracy-toggle tracy-collapsed">source  + " class="tracy-toggle">source  " ?> @@ -128,11 +128,11 @@ $counter = 0;

-
id="tracyBsSrc">
+
id="tracyBsSrc">
-
">
+
">