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) {
|
public function set($key, $value) {
|
||||||
$value = self::normalizeSeparators($value);
|
if(DIRECTORY_SEPARATOR != '/') $value = self::normalizeSeparators($value);
|
||||||
if($key == 'root') {
|
if($key == 'root') {
|
||||||
$this->_root = $value;
|
$this->_root = $value;
|
||||||
return $this;
|
return $this;
|
||||||
@@ -159,7 +159,7 @@ class Paths extends WireData {
|
|||||||
*/
|
*/
|
||||||
public function get($key) {
|
public function get($key) {
|
||||||
static $_http = null;
|
static $_http = null;
|
||||||
if($key == 'root') return $this->_root;
|
if($key === 'root') return $this->_root;
|
||||||
$http = '';
|
$http = '';
|
||||||
if(is_object($key)) {
|
if(is_object($key)) {
|
||||||
$key = "$key";
|
$key = "$key";
|
||||||
@@ -174,7 +174,7 @@ class Paths extends WireData {
|
|||||||
$key = substr($key, 4);
|
$key = substr($key, 4);
|
||||||
$key[0] = strtolower($key[0]);
|
$key[0] = strtolower($key[0]);
|
||||||
}
|
}
|
||||||
if($key == 'root') {
|
if($key === 'root') {
|
||||||
$value = $http . $this->_root;
|
$value = $http . $this->_root;
|
||||||
} else {
|
} else {
|
||||||
$value = parent::get($key);
|
$value = parent::get($key);
|
||||||
|
@@ -424,7 +424,7 @@ class ProcessWire extends Wire {
|
|||||||
$fieldtypes = $this->wire('fieldtypes', new Fieldtypes(), true);
|
$fieldtypes = $this->wire('fieldtypes', new Fieldtypes(), true);
|
||||||
$fields = $this->wire('fields', new Fields(), true);
|
$fields = $this->wire('fields', new Fields(), true);
|
||||||
$fieldgroups = $this->wire('fieldgroups', new Fieldgroups(), 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);
|
$pages = $this->wire('pages', new Pages($this), true);
|
||||||
|
|
||||||
$this->initVar('fieldtypes', $fieldtypes);
|
$this->initVar('fieldtypes', $fieldtypes);
|
||||||
|
@@ -792,9 +792,11 @@ class Template extends WireData implements Saveable, Exportable {
|
|||||||
if(empty($value)) return;
|
if(empty($value)) return;
|
||||||
|
|
||||||
if(strpos($value, '/') === false) {
|
if(strpos($value, '/') === false) {
|
||||||
|
// value is basename
|
||||||
$value = $this->config->paths->templates . $value;
|
$value = $this->config->paths->templates . $value;
|
||||||
|
|
||||||
} else if(strpos($value, $this->config->paths->root) !== 0) {
|
} 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);
|
$value = $this->config->paths->templates . basename($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -878,35 +880,52 @@ class Template extends WireData implements Saveable, Exportable {
|
|||||||
*/
|
*/
|
||||||
public function filename() {
|
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->settings['name']) {
|
||||||
|
throw new WireException("Template must be assigned a name before 'filename' can be accessed");
|
||||||
|
}
|
||||||
|
|
||||||
if($this->altFilename) {
|
if($altFilename) {
|
||||||
$altFilename = $this->wire('templates')->path . basename($this->altFilename, "." . $this->config->templateExtension) . "." . $this->config->templateExtension;
|
$filename = $path . basename($altFilename, $ext) . $ext;
|
||||||
$this->filename = $altFilename;
|
|
||||||
} else {
|
} else {
|
||||||
$this->filename = $this->wire('templates')->path . $this->settings['name'] . '.' . $this->config->templateExtension;
|
$filename = $path . $this->settings['name'] . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($filename !== $this->filename) {
|
||||||
|
// first set of filename, or filename/path has been changed
|
||||||
|
$this->filenameExists = null;
|
||||||
|
$this->filename = $filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
$isModified = false;
|
|
||||||
$fileExists = $this->filenameExists();
|
|
||||||
|
|
||||||
if($fileExists) {
|
if($this->filenameExists === null) {
|
||||||
$modified = filemtime($this->filename);
|
$this->filenameExists = file_exists($filename);
|
||||||
if($modified > $this->modified) {
|
if($this->filenameExists) {
|
||||||
$isModified = true;
|
// if filename exists, keep track of last modification time
|
||||||
$this->modified = $modified;
|
$isModified = false;
|
||||||
}
|
$modified = filemtime($filename);
|
||||||
if($isModified || !$this->ns) {
|
if($modified > $this->modified) {
|
||||||
// determine namespace
|
$isModified = true;
|
||||||
$this->ns = $this->wire('files')->getNamespace($this->filename);
|
$this->modified = $modified;
|
||||||
// tell it to save the template after the request is finished
|
}
|
||||||
$this->addHookAfter('ProcessWire::finished', $this, 'hookFinished');
|
if($isModified || !$this->ns) {
|
||||||
|
// determine namespace
|
||||||
|
$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
|
* #pw-group-files
|
||||||
*
|
*
|
||||||
* @return string
|
* @return bool
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function filenameExists() {
|
public function filenameExists() {
|
||||||
if(!is_null($this->filenameExists)) return $this->filenameExists;
|
if($this->filenameExists !== null) return $this->filenameExists;
|
||||||
$this->filenameExists = file_exists($this->filename());
|
$this->filenameExists = file_exists($this->filename());
|
||||||
return $this->filenameExists;
|
return $this->filenameExists;
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Manages and provides access to all the Template instances
|
* 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
|
* https://processwire.com
|
||||||
*
|
*
|
||||||
* #pw-summary Manages and provides access to all the Templates.
|
* #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 bool|Saveable|Template clone(Saveable $item, $name = '') #pw-internal
|
||||||
* @method array getExportData(Template $template) Export Template data for external use. #pw-advanced
|
* @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 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 {
|
class Templates extends WireSaveableItems {
|
||||||
@@ -30,26 +31,26 @@ class Templates extends WireSaveableItems {
|
|||||||
* WireArray of all Template instances
|
* WireArray of all Template instances
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $templatesArray;
|
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
|
* Construct the Templates
|
||||||
*
|
*
|
||||||
* @param Fieldgroups $fieldgroups Reference to the Fieldgroups
|
* @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);
|
$fieldgroups->wire($this);
|
||||||
$this->fieldgroups = $fieldgroups;
|
$this->fieldgroups = $fieldgroups;
|
||||||
$this->templatesArray = $this->wire(new TemplatesArray());
|
$this->templatesArray = $this->wire(new TemplatesArray());
|
||||||
$this->path = $path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,7 +114,7 @@ class Templates extends WireSaveableItems {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function get($key) {
|
public function get($key) {
|
||||||
if($key == 'path') return $this->path;
|
if($key == 'path') return $this->wire('config')->paths->templates;
|
||||||
$value = $this->templatesArray->get($key);
|
$value = $this->templatesArray->get($key);
|
||||||
if(is_null($value)) $value = parent::get($key);
|
if(is_null($value)) $value = parent::get($key);
|
||||||
return $value;
|
return $value;
|
||||||
@@ -652,6 +653,44 @@ class Templates extends WireSaveableItems {
|
|||||||
return $updated;
|
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?
|
* 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) {
|
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
|
// this object has not yet been wired! use last known current instance as fallback
|
||||||
// note this condition is unsafe in multi-instance mode
|
// note this condition is unsafe in multi-instance mode
|
||||||
$wire = ProcessWire::getCurrentInstance();
|
$wire = ProcessWire::getCurrentInstance();
|
||||||
|
Reference in New Issue
Block a user