123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <?php
- /**
- * @package Grav\Installer
- *
- * @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
- * @license MIT License; see LICENSE file for details.
- */
- namespace Grav\Installer;
- use Symfony\Component\Yaml\Yaml;
- use function is_array;
- use function is_string;
- /**
- * Grav Versions
- *
- * NOTE: This class can be initialized during upgrade from an older version of Grav. Make sure it runs there!
- */
- final class Versions
- {
- /** @var string */
- protected $filename;
- /** @var array */
- protected $items;
- /** @var bool */
- protected $updated = false;
- /** @var self[] */
- protected static $instance;
- /**
- * @param string|null $filename
- * @return self
- */
- public static function instance(string $filename = null): self
- {
- $filename = $filename ?? USER_DIR . 'config/versions.yaml';
- if (!isset(self::$instance[$filename])) {
- self::$instance[$filename] = new self($filename);
- }
- return self::$instance[$filename];
- }
- /**
- * @return bool True if the file was updated.
- */
- public function save(): bool
- {
- if (!$this->updated) {
- return false;
- }
- file_put_contents($this->filename, Yaml::dump($this->items, 4, 2));
- $this->updated = false;
- return true;
- }
- /**
- * @return array
- */
- public function getAll(): array
- {
- return $this->items;
- }
- /**
- * @return array|null
- */
- public function getGrav(): ?array
- {
- return $this->get('core/grav');
- }
- /**
- * @return array
- */
- public function getPlugins(): array
- {
- return $this->get('plugins', []);
- }
- /**
- * @param string $name
- * @return array|null
- */
- public function getPlugin(string $name): ?array
- {
- return $this->get("plugins/{$name}");
- }
- /**
- * @return array
- */
- public function getThemes(): array
- {
- return $this->get('themes', []);
- }
- /**
- * @param string $name
- * @return array|null
- */
- public function getTheme(string $name): ?array
- {
- return $this->get("themes/{$name}");
- }
- /**
- * @param string $extension
- * @return array|null
- */
- public function getExtension(string $extension): ?array
- {
- return $this->get($extension);
- }
- /**
- * @param string $extension
- * @param array|null $value
- */
- public function setExtension(string $extension, ?array $value): void
- {
- if (null !== $value) {
- $this->set($extension, $value);
- } else {
- $this->undef($extension);
- }
- }
- /**
- * @param string $extension
- * @return string|null
- */
- public function getVersion(string $extension): ?string
- {
- $version = $this->get("{$extension}/version", null);
- return is_string($version) ? $version : null;
- }
- /**
- * @param string $extension
- * @param string|null $version
- */
- public function setVersion(string $extension, ?string $version): void
- {
- $this->updateHistory($extension, $version);
- }
- /**
- * NOTE: Updates also history.
- *
- * @param string $extension
- * @param string|null $version
- */
- public function updateVersion(string $extension, ?string $version): void
- {
- $this->set("{$extension}/version", $version);
- $this->updateHistory($extension, $version);
- }
- /**
- * @param string $extension
- * @return string|null
- */
- public function getSchema(string $extension): ?string
- {
- $version = $this->get("{$extension}/schema", null);
- return is_string($version) ? $version : null;
- }
- /**
- * @param string $extension
- * @param string|null $schema
- */
- public function setSchema(string $extension, ?string $schema): void
- {
- if (null !== $schema) {
- $this->set("{$extension}/schema", $schema);
- } else {
- $this->undef("{$extension}/schema");
- }
- }
- /**
- * @param string $extension
- * @return array
- */
- public function getHistory(string $extension): array
- {
- $name = "{$extension}/history";
- $history = $this->get($name, []);
- // Fix for broken Grav 1.6 history
- if ($extension === 'grav') {
- $history = $this->fixHistory($history);
- }
- return $history;
- }
- /**
- * @param string $extension
- * @param string|null $version
- */
- public function updateHistory(string $extension, ?string $version): void
- {
- $name = "{$extension}/history";
- $history = $this->getHistory($extension);
- $history[] = ['version' => $version, 'date' => gmdate('Y-m-d H:i:s')];
- $this->set($name, $history);
- }
- /**
- * Clears extension history. Useful when creating skeletons.
- *
- * @param string $extension
- */
- public function removeHistory(string $extension): void
- {
- $this->undef("{$extension}/history");
- }
- /**
- * @param array $history
- * @return array
- */
- private function fixHistory(array $history): array
- {
- if (isset($history['version'], $history['date'])) {
- $fix = [['version' => $history['version'], 'date' => $history['date']]];
- unset($history['version'], $history['date']);
- $history = array_merge($fix, $history);
- }
- return $history;
- }
- /**
- * Get value by using dot notation for nested arrays/objects.
- *
- * @param string $name Slash separated path to the requested value.
- * @param mixed $default Default value (or null).
- * @return mixed Value.
- */
- private function get(string $name, $default = null)
- {
- $path = explode('/', $name);
- $current = $this->items;
- foreach ($path as $field) {
- if (is_array($current) && isset($current[$field])) {
- $current = $current[$field];
- } else {
- return $default;
- }
- }
- return $current;
- }
- /**
- * Set value by using dot notation for nested arrays/objects.
- *
- * @param string $name Slash separated path to the requested value.
- * @param mixed $value New value.
- */
- private function set(string $name, $value): void
- {
- $path = explode('/', $name);
- $current = &$this->items;
- foreach ($path as $field) {
- // Handle arrays and scalars.
- if (!is_array($current)) {
- $current = [$field => []];
- } elseif (!isset($current[$field])) {
- $current[$field] = [];
- }
- $current = &$current[$field];
- }
- $current = $value;
- $this->updated = true;
- }
- /**
- * Unset value by using dot notation for nested arrays/objects.
- *
- * @param string $name Dot separated path to the requested value.
- */
- private function undef(string $name): void
- {
- $path = $name !== '' ? explode('/', $name) : [];
- if (!$path) {
- return;
- }
- $var = array_pop($path);
- $current = &$this->items;
- foreach ($path as $field) {
- if (!is_array($current) || !isset($current[$field])) {
- return;
- }
- $current = &$current[$field];
- }
- unset($current[$var]);
- $this->updated = true;
- }
- private function __construct(string $filename)
- {
- $this->filename = $filename;
- $content = is_file($filename) ? file_get_contents($filename) : null;
- if (false === $content) {
- throw new \RuntimeException('Versions file cannot be read');
- }
- $this->items = $content ? Yaml::parse($content) : [];
- }
- }
|