summaryrefslogtreecommitdiff
path: root/app/php/web
diff options
context:
space:
mode:
Diffstat (limited to 'app/php/web')
-rw-r--r--app/php/web/AssetManager.php29
-rw-r--r--app/php/web/ClientScriptManager.php243
-rw-r--r--app/php/web/TemplateControl.php53
-rw-r--r--app/php/web/config.xml7
4 files changed, 332 insertions, 0 deletions
diff --git a/app/php/web/AssetManager.php b/app/php/web/AssetManager.php
new file mode 100644
index 0000000..1094917
--- /dev/null
+++ b/app/php/web/AssetManager.php
@@ -0,0 +1,29 @@
+<?php
+
+class AssetManager extends TAssetManager {
+
+ public function init($config) {
+ if ($this->BaseUrl === NULL) {
+ $appWebPath = preg_replace(
+ '#' . $this->Application->Request->ApplicationUrl . '$#',
+ '',
+ $this->Application->Request->ApplicationFilePath
+ );
+ $appBaseUrl = preg_replace(
+ '#^' . $appWebPath . '#',
+ '',
+ dirname($this->Application->Request->ApplicationFilePath)
+ );
+ $this->BaseUrl = $appBaseUrl
+ . preg_replace(
+ '#^' . Prado::getPathOfNamespace('Web') . '#',
+ '',
+ $this->BasePath
+ );
+ }
+ parent::init($config);
+ }
+
+}
+
+?>
diff --git a/app/php/web/ClientScriptManager.php b/app/php/web/ClientScriptManager.php
new file mode 100644
index 0000000..84b9d6f
--- /dev/null
+++ b/app/php/web/ClientScriptManager.php
@@ -0,0 +1,243 @@
+<?php
+
+Prado::using('Application.layouts.Layout');
+
+class ClientScriptManager extends TClientScriptManager {
+
+ private $_page;
+ public function __construct(TPage $page) {
+ $this->_page = $page;
+ parent::__construct($page);
+ }
+
+ private function _getBasePath() {
+ return Prado::getPathOfNamespace('Web') . DIRECTORY_SEPARATOR;
+ }
+
+ private function _getBasePaths($urls) {
+ $basePath = $this->_getBasePath();
+ return array_map(
+ function($path) use($basePath) {
+ return $basePath . DIRECTORY_SEPARATOR . $path;
+ },
+ $urls
+ );
+ }
+
+ private function _getCachePath($subdir = 'assets') {
+ $cachePath = $this->Application->RuntimePath
+ . DIRECTORY_SEPARATOR
+ . $subdir;
+ if (!is_dir($cachePath)) {
+ if (file_exists($cachePath)) {
+ throw new TIOException(
+ 'Client script manager cache path "'
+ . $cachePath
+ . ' "exists and is not a directory'
+ );
+ } else {
+ mkdir($cachePath);
+ }
+ }
+ return $cachePath;
+ }
+
+ private function _getCacheFilePath($path, $type) {
+ return $this->_getCachePath($type)
+ . DIRECTORY_SEPARATOR
+ . $path;
+ }
+
+ private function _getFileCollectionCacheKey($files) {
+ sort($files);
+ return md5(implode(PHP_EOL, $files));
+ }
+
+ private function _getFileCollectionMTime($files) {
+ return max(array_map('filemtime', $files));
+ }
+
+ private $_renderedScriptsInitialized = FALSE;
+
+ private function _getRenderedScriptsStoreKey() {
+ $template = $this->_page->Master;
+ if (!$template instanceof Layout) {
+ throw new TNotSupportedException(
+ 'Compiled assets may only be used within Layout master class controls'
+ );
+ }
+ return 'RenderedScripts.' . $template->generateViewID();
+ }
+
+ private function _getCache() {
+ $cache = $this->Application->Cache;
+ if (!$cache) {
+ throw new TNotSupportedException(
+ 'Compiled assets require cache to be configured'
+ );
+ }
+ return $cache;
+ }
+
+ private function _getRenderedScripts() {
+ $sessionKey = $this->_getRenderedScriptsStoreKey();
+ if ($this->_page->IsCallBack || $this->_renderedScriptsInitialized) {
+ return $this->_getCache()->get($sessionKey) ?: [];
+ } else {
+ $this->_getCache()->delete($sessionKey);
+ $this->_renderedScriptsInitialized = TRUE;
+ return [];
+ }
+ }
+
+ private function _appendRenderedScripts(array $newScripts, $compiledFileKey) {
+ $scripts = $this->_getRenderedScripts();
+ if (!isset($scripts[$compiledFileKey])) {
+ $scripts[$compiledFileKey] = [];
+ }
+ $scripts[$compiledFileKey] = array_unique(
+ array_merge(
+ $scripts[$compiledFileKey],
+ $newScripts
+ )
+ );
+ $this->_getCache()->set(
+ $this->_getRenderedScriptsStoreKey(),
+ $scripts
+ );
+ }
+
+ private function _compileFiles($files) {
+ foreach ($files as $file) {
+ $this->markScriptFileAsRendered($file);
+ }
+ $paths = $this->_getBasePaths($files);
+ $cacheKey = $this->_getFileCollectionCacheKey($paths);
+ $cacheFile = $this->_getCacheFilePath($cacheKey . '.js', 'scripts');
+ $this->_appendRenderedScripts($files, $cacheFile);
+ if (!file_exists($cacheFile)
+ || (filemtime($cacheFile)
+ < $this->_getFileCollectionMTime($paths))) {
+ $scriptContent = implode(
+ PHP_EOL,
+ array_map(
+ function($path) {
+ return trim(
+ TJavaScript::JSMin(
+ file_get_contents($path)
+ )
+ );
+ },
+ $paths
+ )
+ );
+ file_put_contents($cacheFile, $scriptContent);
+ }
+ return $this->Application->AssetManager->publishFilePath($cacheFile);
+ }
+
+ private function _determineLocalScriptFiles($files) {
+ $basePath = $this->_getBasePath();
+ return array_filter(
+ $files,
+ function($file) use($basePath) {
+ return file_exists($basePath . DIRECTORY_SEPARATOR . $file);
+ }
+ );
+ }
+
+ private function _renderLocalScriptFiles($writer, $localFiles) {
+ if ($localFiles) {
+ $assetPath = $this->_compileFiles($localFiles);
+ $writer->write(TJavascript::renderScriptFile($assetPath));
+ }
+ }
+
+ private function _renderExternalScriptFiles($writer, $externalFiles) {
+ if ($externalFiles) {
+ foreach ($externalFiles as $file) {
+ $this->markScriptFileAsRendered($file);
+ $this->_appendRenderedScripts([$file], $file);
+ }
+ parent::renderScriptFiles($writer, $externalFiles);
+ }
+ }
+
+ public function renderScriptFiles($writer, Array $files) {
+ if ($this->getApplication()->getMode() !== TApplicationMode::Debug) {
+ if ($files) {
+ $localFiles = $this->_determineLocalScriptFiles($files);
+ $this->_renderLocalScriptFiles($writer, $localFiles);
+ $externalFiles = array_diff($files, $localFiles);
+ $this->_renderExternalScriptFiles($writer, $externalFiles);
+ }
+ } else {
+ parent::renderScriptFiles($writer, $files);
+ }
+ }
+
+ private function _getRenderedScriptUrl($registeredScript) {
+ $renderedScripts = $this->_getRenderedScripts();
+ foreach ($renderedScripts as $compiledFile => $scripts) {
+ if (in_array($registeredScript, $scripts)) {
+ if (file_exists($compiledFile)) {
+ return $this->Application->AssetManager->getPublishedUrl(
+ $compiledFile
+ );
+ } else {
+ return $registeredScript;
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ public function getScriptUrls() {
+ if ($this->getApplication()->getMode() !== TApplicationMode::Debug) {
+ $registeredScripts = array_unique(
+ array_merge(
+ $this->_scripts, $this->_headScripts
+ )
+ );
+ $scriptUrls = [];
+ $newScripts = [];
+ foreach ($registeredScripts as $registeredScript) {
+ $renderedScriptUrl = $this->_getRenderedScriptUrl(
+ $registeredScript
+ );
+ if ($renderedScriptUrl) {
+ $scriptUrls[] = $renderedScriptUrl;
+ } else {
+ $newScripts[] = $registeredScript;
+ }
+ }
+ $newLocalScripts = $this->_determineLocalScriptFiles($newScripts);
+ $newRemoteScripts = array_diff($newScripts, $newLocalScripts);
+ if ($newLocalScripts) {
+ $scriptUrls[] = $this->_compileFiles($newLocalScripts);
+ }
+ $scriptUrls = array_values(
+ array_unique(array_merge($scriptUrls, $newRemoteScripts))
+ );
+ return $scriptUrls;
+ } else {
+ return parent::getScriptUrls();
+ }
+ }
+
+ private $_scripts = [];
+ private $_headScripts = [];
+
+ public function registerScriptFile($key, $file) {
+ $this->_scripts[$key] = $file;
+ return parent::registerScriptFile($key, $file);
+ }
+
+ public function registerHeadScriptFile($key, $file) {
+ $this->_headScripts[$key] = $file;
+ return parent::registerHeadScriptFile($key, $file);
+ }
+
+}
+
+?>
diff --git a/app/php/web/TemplateControl.php b/app/php/web/TemplateControl.php
new file mode 100644
index 0000000..e3c9e26
--- /dev/null
+++ b/app/php/web/TemplateControl.php
@@ -0,0 +1,53 @@
+<?php
+
+class TemplateControl extends TTemplateControl {
+
+ private function _getControlScriptPath($className) {
+ return Prado::getPathOfNamespace('Application.controls.scripts')
+ . DIRECTORY_SEPARATOR
+ . $className
+ . '.js';
+ }
+
+ public function onPreRender($param) {
+ parent::onPreRender($param);
+ $scriptFile = $this->_getControlScriptPath(get_class($this));
+ if (file_exists($scriptFile)) {
+ foreach ($this->getPradoScriptDependencies() as $dependency) {
+ $this->Page->ClientScript->registerPradoScript($dependency);
+ }
+ foreach ($this->getControlScriptDependencies() as $dependency) {
+ $this->Page->ClientScript->registerScriptFile(
+ 'TemplateControl.' . $dependency,
+ $this->Application->AssetManager->publishFilePath(
+ $this->_getControlScriptPath($dependency)
+ )
+ );
+ }
+ foreach ($this->getExternalScriptDependencies() as $dependency) {
+ $this->Page->ClientScript->registerHeadScriptFile(
+ $dependency, $dependency
+ );
+ }
+ $this->Page->ClientScript->registerScriptFile(
+ 'TemplateControl.' . get_class($this),
+ $this->Application->AssetManager->publishFilePath($scriptFile)
+ );
+ }
+ }
+
+ protected function getPradoScriptDependencies() {
+ return [];
+ }
+
+ protected function getControlScriptDependencies() {
+ return [];
+ }
+
+ protected function getExternalScriptDependencies() {
+ return [];
+ }
+
+}
+
+?>
diff --git a/app/php/web/config.xml b/app/php/web/config.xml
new file mode 100644
index 0000000..49bbcc6
--- /dev/null
+++ b/app/php/web/config.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <modules>
+ <module id="asset" class="Application.web.AssetManager"
+ BasePath="Web._assets" />
+ </modules>
+</configuration>