grav/system/src/Grav/Common/Config/CompiledBase.php

270 lines
6.1 KiB
PHP
Raw Normal View History

2015-11-18 14:14:27 +01:00
<?php
2019-01-31 09:04:57 +01:00
2016-07-12 00:07:14 +02:00
/**
2019-01-31 09:04:57 +01:00
* @package Grav\Common\Config
2016-07-12 00:07:14 +02:00
*
2023-01-02 19:09:32 +01:00
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
2016-07-12 00:07:14 +02:00
* @license MIT License; see LICENSE file for details.
*/
2015-11-18 14:14:27 +01:00
namespace Grav\Common\Config;
use BadMethodCallException;
use Exception;
2015-11-18 14:14:27 +01:00
use RocketTheme\Toolbox\File\PhpFile;
use RuntimeException;
use function get_class;
use function is_array;
2015-11-18 14:14:27 +01:00
/**
* Class CompiledBase
* @package Grav\Common\Config
*/
2015-11-18 14:14:27 +01:00
abstract class CompiledBase
{
/** @var int Version number for the compiled file. */
2015-11-18 14:14:27 +01:00
public $version = 1;
/** @var string Filename (base name) of the compiled configuration. */
2015-11-18 14:14:27 +01:00
public $name;
/** @var string|bool Configuration checksum. */
2015-11-18 14:14:27 +01:00
public $checksum;
/** @var int Timestamp of compiled configuration */
public $timestamp = 0;
/** @var string Cache folder to be used. */
2015-11-18 14:14:27 +01:00
protected $cacheFolder;
/** @var array List of files to load. */
2015-11-18 14:14:27 +01:00
protected $files;
/** @var string */
2015-11-18 14:14:27 +01:00
protected $path;
/** @var mixed Configuration object. */
2015-11-18 14:14:27 +01:00
protected $object;
/**
* @param string $cacheFolder Cache folder to be used.
* @param array $files List of files as returned from ConfigFileFinder class.
* @param string $path Base path for the file list.
* @throws BadMethodCallException
2015-11-18 14:14:27 +01:00
*/
public function __construct($cacheFolder, array $files, $path)
{
if (!$cacheFolder) {
throw new BadMethodCallException('Cache folder not defined.');
2015-11-18 14:14:27 +01:00
}
$this->path = $path ? rtrim($path, '\\/') . '/' : '';
2015-11-18 14:14:27 +01:00
$this->cacheFolder = $cacheFolder;
$this->files = $files;
}
/**
* Get filename for the compiled PHP file.
*
* @param string|null $name
2015-11-18 14:14:27 +01:00
* @return $this
*/
public function name($name = null)
{
if (!$this->name) {
$this->name = $name ?: md5(json_encode(array_keys($this->files)));
}
return $this;
}
/**
2015-11-19 11:02:08 +01:00
* Function gets called when cached configuration is saved.
*
* @return void
2015-11-18 14:14:27 +01:00
*/
2019-10-14 09:57:26 +02:00
public function modified()
{
}
2015-11-18 14:14:27 +01:00
/**
* Get timestamp of compiled configuration
*
* @return int Timestamp of compiled configuration
*/
public function timestamp()
{
return $this->timestamp ?: time();
}
2015-11-18 14:14:27 +01:00
/**
* Load the configuration.
*
* @return mixed
*/
public function load()
{
if ($this->object) {
return $this->object;
}
$filename = $this->createFilename();
if (!$this->loadCompiledFile($filename) && $this->loadFiles()) {
$this->saveCompiledFile($filename);
}
return $this->object;
}
/**
* Returns checksum from the configuration files.
*
* You can set $this->checksum = false to disable this check.
*
* @return bool|string
*/
public function checksum()
{
2018-09-14 14:36:25 +02:00
if (null === $this->checksum) {
2015-11-18 14:14:27 +01:00
$this->checksum = md5(json_encode($this->files) . $this->version);
}
return $this->checksum;
}
/**
* @return string
*/
2015-11-18 14:14:27 +01:00
protected function createFilename()
{
return "{$this->cacheFolder}/{$this->name()->name}.php";
}
/**
* Create configuration object.
*
* @param array $data
* @return void
2015-11-18 14:14:27 +01:00
*/
abstract protected function createObject(array $data = []);
2015-11-19 11:02:08 +01:00
/**
* Finalize configuration object.
*
* @return void
2015-11-19 11:02:08 +01:00
*/
abstract protected function finalizeObject();
2015-11-18 14:14:27 +01:00
/**
* Load single configuration file and append it to the correct position.
*
* @param string $name Name of the position.
* @param string|string[] $filename File(s) to be loaded.
2020-12-10 22:15:02 +01:00
* @return void
2015-11-18 14:14:27 +01:00
*/
abstract protected function loadFile($name, $filename);
/**
* Load and join all configuration files.
*
* @return bool
* @internal
*/
protected function loadFiles()
{
$this->createObject();
$list = array_reverse($this->files);
foreach ($list as $files) {
foreach ($files as $name => $item) {
$this->loadFile($name, $this->path . $item['file']);
}
}
2015-11-19 11:02:08 +01:00
$this->finalizeObject();
2015-11-18 14:14:27 +01:00
return true;
}
/**
* Load compiled file.
*
* @param string $filename
* @return bool
* @internal
*/
protected function loadCompiledFile($filename)
{
if (!file_exists($filename)) {
return false;
}
$cache = include $filename;
if (!is_array($cache)
2019-01-31 16:32:06 +01:00
|| !isset($cache['checksum'], $cache['data'], $cache['@class'])
|| $cache['@class'] !== get_class($this)
2015-11-18 14:14:27 +01:00
) {
return false;
}
// Load real file if cache isn't up to date (or is invalid).
if ($cache['checksum'] !== $this->checksum()) {
return false;
}
$this->createObject($cache['data']);
2018-09-14 14:36:25 +02:00
$this->timestamp = $cache['timestamp'] ?? 0;
2016-07-12 00:07:14 +02:00
$this->finalizeObject();
2016-07-12 00:07:14 +02:00
2015-11-18 14:14:27 +01:00
return true;
}
/**
* Save compiled file.
*
* @param string $filename
2020-12-10 22:15:02 +01:00
* @return void
* @throws RuntimeException
2015-11-18 14:14:27 +01:00
* @internal
*/
protected function saveCompiledFile($filename)
{
$file = PhpFile::instance($filename);
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (Exception $e) {
2015-11-18 14:14:27 +01:00
// Another process has locked the file; we will check this in a bit.
}
if ($file->locked() === false) {
// File was already locked by another process.
return;
}
$cache = [
'@class' => get_class($this),
2015-11-18 14:14:27 +01:00
'timestamp' => time(),
'checksum' => $this->checksum(),
'files' => $this->files,
2016-02-18 16:09:27 +01:00
'data' => $this->getState()
2015-11-18 14:14:27 +01:00
];
$file->save($cache);
$file->unlock();
$file->free();
2015-11-19 11:02:08 +01:00
$this->modified();
2015-11-18 14:14:27 +01:00
}
2016-02-18 16:09:27 +01:00
/**
* @return array
*/
2016-02-18 16:09:27 +01:00
protected function getState()
{
return $this->object->toArray();
}
2015-11-18 14:14:27 +01:00
}