mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 00:06:55 +02:00
Add a new Templates::fileModified() hookable method that is called whenever a change is detected to a template file. Plus update the Template and Templates class to make it possible for runtime modification of the templates path.
This commit is contained in:
@@ -140,7 +140,7 @@ class Paths extends WireData {
|
||||
*
|
||||
*/
|
||||
public function set($key, $value) {
|
||||
$value = self::normalizeSeparators($value);
|
||||
if(DIRECTORY_SEPARATOR != '/') $value = self::normalizeSeparators($value);
|
||||
if($key == 'root') {
|
||||
$this->_root = $value;
|
||||
return $this;
|
||||
@@ -159,7 +159,7 @@ class Paths extends WireData {
|
||||
*/
|
||||
public function get($key) {
|
||||
static $_http = null;
|
||||
if($key == 'root') return $this->_root;
|
||||
if($key === 'root') return $this->_root;
|
||||
$http = '';
|
||||
if(is_object($key)) {
|
||||
$key = "$key";
|
||||
@@ -174,7 +174,7 @@ class Paths extends WireData {
|
||||
$key = substr($key, 4);
|
||||
$key[0] = strtolower($key[0]);
|
||||
}
|
||||
if($key == 'root') {
|
||||
if($key === 'root') {
|
||||
$value = $http . $this->_root;
|
||||
} else {
|
||||
$value = parent::get($key);
|
||||
|
@@ -424,7 +424,7 @@ class ProcessWire extends Wire {
|
||||
$fieldtypes = $this->wire('fieldtypes', new Fieldtypes(), true);
|
||||
$fields = $this->wire('fields', new Fields(), true);
|
||||
$fieldgroups = $this->wire('fieldgroups', new Fieldgroups(), true);
|
||||
$templates = $this->wire('templates', new Templates($fieldgroups, $config->paths->templates), true);
|
||||
$templates = $this->wire('templates', new Templates($fieldgroups), true);
|
||||
$pages = $this->wire('pages', new Pages($this), true);
|
||||
|
||||
$this->initVar('fieldtypes', $fieldtypes);
|
||||
|
@@ -792,9 +792,11 @@ class Template extends WireData implements Saveable, Exportable {
|
||||
if(empty($value)) return;
|
||||
|
||||
if(strpos($value, '/') === false) {
|
||||
// value is basename
|
||||
$value = $this->config->paths->templates . $value;
|
||||
|
||||
} else if(strpos($value, $this->config->paths->root) !== 0) {
|
||||
// value is path outside of our installation root, which we do not accept
|
||||
$value = $this->config->paths->templates . basename($value);
|
||||
}
|
||||
|
||||
@@ -878,35 +880,52 @@ class Template extends WireData implements Saveable, Exportable {
|
||||
*/
|
||||
public function filename() {
|
||||
|
||||
if($this->filename) return $this->filename;
|
||||
/** @var Config $config */
|
||||
$config = $this->wire('config');
|
||||
$path = $config->paths->templates;
|
||||
$ext = '.' . $config->templateExtension;
|
||||
$altFilename = $this->altFilename;
|
||||
|
||||
if(!$this->settings['name']) throw new WireException("Template must be assigned a name before 'filename' can be accessed");
|
||||
|
||||
if($this->altFilename) {
|
||||
$altFilename = $this->wire('templates')->path . basename($this->altFilename, "." . $this->config->templateExtension) . "." . $this->config->templateExtension;
|
||||
$this->filename = $altFilename;
|
||||
} else {
|
||||
$this->filename = $this->wire('templates')->path . $this->settings['name'] . '.' . $this->config->templateExtension;
|
||||
if(!$this->settings['name']) {
|
||||
throw new WireException("Template must be assigned a name before 'filename' can be accessed");
|
||||
}
|
||||
|
||||
$isModified = false;
|
||||
$fileExists = $this->filenameExists();
|
||||
if($altFilename) {
|
||||
$filename = $path . basename($altFilename, $ext) . $ext;
|
||||
} else {
|
||||
$filename = $path . $this->settings['name'] . $ext;
|
||||
}
|
||||
|
||||
if($fileExists) {
|
||||
$modified = filemtime($this->filename);
|
||||
if($filename !== $this->filename) {
|
||||
// first set of filename, or filename/path has been changed
|
||||
$this->filenameExists = null;
|
||||
$this->filename = $filename;
|
||||
}
|
||||
|
||||
if($this->filenameExists === null) {
|
||||
$this->filenameExists = file_exists($filename);
|
||||
if($this->filenameExists) {
|
||||
// if filename exists, keep track of last modification time
|
||||
$isModified = false;
|
||||
$modified = filemtime($filename);
|
||||
if($modified > $this->modified) {
|
||||
$isModified = true;
|
||||
$this->modified = $modified;
|
||||
}
|
||||
if($isModified || !$this->ns) {
|
||||
// determine namespace
|
||||
$this->ns = $this->wire('files')->getNamespace($this->filename);
|
||||
// tell it to save the template after the request is finished
|
||||
$this->addHookAfter('ProcessWire::finished', $this, 'hookFinished');
|
||||
$files = $this->wire('files');
|
||||
/** @var WireFileTools $files */
|
||||
$templates = $this->wire('templates');
|
||||
/** @var Templates $templates */
|
||||
$this->ns = $files->getNamespace($filename);
|
||||
$templates->fileModified($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->filename;
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -928,11 +947,11 @@ class Template extends WireData implements Saveable, Exportable {
|
||||
*
|
||||
* #pw-group-files
|
||||
*
|
||||
* @return string
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function filenameExists() {
|
||||
if(!is_null($this->filenameExists)) return $this->filenameExists;
|
||||
if($this->filenameExists !== null) return $this->filenameExists;
|
||||
$this->filenameExists = file_exists($this->filename());
|
||||
return $this->filenameExists;
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Manages and provides access to all the Template instances
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2019 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* #pw-summary Manages and provides access to all the Templates.
|
||||
@@ -16,6 +16,7 @@
|
||||
* @method bool|Saveable|Template clone(Saveable $item, $name = '') #pw-internal
|
||||
* @method array getExportData(Template $template) Export Template data for external use. #pw-advanced
|
||||
* @method array setImportData(Template $template, array $data) Given an array of Template export data, import it to the given Template. #pw-advanced
|
||||
* @method void fileModified(Template $template) Hook called when a template detects that its file has been modified. #pw-hooker
|
||||
*
|
||||
*/
|
||||
class Templates extends WireSaveableItems {
|
||||
@@ -33,23 +34,23 @@ class Templates extends WireSaveableItems {
|
||||
protected $templatesArray;
|
||||
|
||||
/**
|
||||
* Path where Template files are stored
|
||||
* Templates that had changed files during this request
|
||||
*
|
||||
* @var array Array of Template objects indexed by id
|
||||
*
|
||||
*/
|
||||
protected $path;
|
||||
protected $fileModTemplates = array();
|
||||
|
||||
/**
|
||||
* Construct the Templates
|
||||
*
|
||||
* @param Fieldgroups $fieldgroups Reference to the Fieldgroups
|
||||
* @param string $path Path to where template files are stored
|
||||
*
|
||||
*/
|
||||
public function __construct(Fieldgroups $fieldgroups, $path) {
|
||||
public function __construct(Fieldgroups $fieldgroups) {
|
||||
$fieldgroups->wire($this);
|
||||
$this->fieldgroups = $fieldgroups;
|
||||
$this->templatesArray = $this->wire(new TemplatesArray());
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +114,7 @@ class Templates extends WireSaveableItems {
|
||||
*
|
||||
*/
|
||||
public function get($key) {
|
||||
if($key == 'path') return $this->path;
|
||||
if($key == 'path') return $this->wire('config')->paths->templates;
|
||||
$value = $this->templatesArray->get($key);
|
||||
if(is_null($value)) $value = parent::get($key);
|
||||
return $value;
|
||||
@@ -652,6 +653,44 @@ class Templates extends WireSaveableItems {
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when a Template detects that its file has changed
|
||||
*
|
||||
* Note that the hook is not called until something in the system (like a page render) asks for the template’s filename.
|
||||
* That’s because it would not be efficient for PW to check the file for every template in the system on every request.
|
||||
*
|
||||
* #pw-hooker
|
||||
*
|
||||
* @param Template $template
|
||||
* @since 3.0.141
|
||||
*
|
||||
*/
|
||||
public function ___fileModified(Template $template) {
|
||||
if(empty($this->fileModTemplates)) {
|
||||
// add hook on first call
|
||||
$this->addHookAfter('ProcessWire::finished', $this, '_hookFinished');
|
||||
}
|
||||
$this->fileModTemplates[$template->id] = $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves templates that had modified files to update 'modified' and 'ns' properties after the request is complete
|
||||
*
|
||||
* #pw-internal
|
||||
*
|
||||
* @param HookEvent $e
|
||||
* @since 3.0.141
|
||||
*
|
||||
*/
|
||||
public function _hookFinished(HookEvent $e) {
|
||||
if($e) {}
|
||||
foreach($this->fileModTemplates as $id => $template) {
|
||||
if($template->isChanged('modified') || $template->isChanged('ns')) {
|
||||
$template->save();
|
||||
}
|
||||
}
|
||||
$this->fileModTemplates = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* FUTURE USE: Is the parent/child relationship allowed?
|
||||
|
@@ -1682,7 +1682,7 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
|
||||
*/
|
||||
public function wire($name = '', $value = null, $lock = false) {
|
||||
|
||||
if(is_null($this->_wire)) {
|
||||
if($this->_wire === null) {
|
||||
// this object has not yet been wired! use last known current instance as fallback
|
||||
// note this condition is unsafe in multi-instance mode
|
||||
$wire = ProcessWire::getCurrentInstance();
|
||||
|
Reference in New Issue
Block a user