ModuleAsset

Package framework.modules
Inheritance class ModuleAsset » Module » LsObject
Since 2.0
Source Code /framework/classes/modules/asset/Asset.class.php
Модуль управления статическими файлами css стилей и js сриптов Позволяет сжимать и объединять файлы для более быстрой загрузки

Protected Properties

Hide inherited properties

PropertyTypeDescriptionDefined By
_aBehaviors Список поведений в виде готовых объектов, формируется автоматически LsObject
aAssets array Список файлов по типам ModuleAsset
aBehaviors array Список поведений LsObject
bIsInit bool Указывает на то, была ли проведенна инициализация модуля Module
hDescriptorMergeLock null|resource Дескриптор файла для проверки блокировки ModuleAsset

Public Methods

Hide inherited methods

MethodDescriptionDefined By
AddBehaviorHook() Добавляет хук поведения LsObject
AddCss() Добавляет файл css стиля ModuleAsset
AddJs() Добавляет файл js скрипта ModuleAsset
AttachBehavior() Присоединяет поведение к объекту LsObject
BuildHeadItems() Возвращает HTML код подключения файлов в HEAD'ер страницы ModuleAsset
CheckAssetType() Проверяет корректность типа файла ModuleAsset
CreateObjectType() Создает и возврашает объект типа ModuleAsset
DetachBehavior() Отсоединяет поведение от объекта LsObject
GetBehavior() Возвращает объект поведения по его имени LsObject
GetBehaviors() Возвращает все объекты поведения LsObject
GetFileWeb() Возвращает корректный WEB путь до файла ModuleAsset
GetRealpath() ModuleAsset
Init() Инициалищация модуля ModuleAsset
PrepareParams() Производит предварительную обработку параметров ModuleAsset
Processing() Производит обработку файлов ModuleAsset
RemoveBehaviorHook() Удаляет хук поведения LsObject
RunBehaviorHook() Запускает хук поведения на выполнение LsObject
SetInit() Помечает модуль как инициализированный Module
Shutdown() ModuleAsset
__call() Ставим хук на вызов неизвестного метода и считаем что хотели вызвать метод какого либо модуля LsObject
__clone() Блокируем копирование/клонирование объекта Module
__construct() Конструктор, запускается автоматически при создании объекта LsObject
__get() Обработка доступа к объекты поведения LsObject
isInit() Возвращает значение флага инициализации модуля Module

Protected Methods

Hide inherited methods

MethodDescriptionDefined By
Add() Добавляет новый файл ModuleAsset
InitAssets() Задает начальную структуры для хранения списка файлов по типам ModuleAsset
IsLockMerge() Проверяет на блокировку ModuleAsset
Merge() Производит объединение и сжатие файлов ModuleAsset
NormalizeFilePath() Приводит путь до файла к единому виду ModuleAsset
PrepareBehaviors() Инициализация поведений LsObject
RemoveLockMerge() Удаляет блокировку ModuleAsset

Property Details

aAssets property
protected array $aAssets;

Список файлов по типам

See Also

hDescriptorMergeLock property
protected null|resource $hDescriptorMergeLock;

Дескриптор файла для проверки блокировки

Method Details

Add() method
protected bool Add(string $sFile, array $aParams, string $sType, bool $bPrepend=false, bool $bReplace=false)
$sFile string Полный путь до файла
$aParams array Дополнительные параметры
$sType string Тип файла
$bPrepend bool Добавлять файл в начало общего списка или нет
$bReplace bool Если такой файл уже добавлен, то заменяет его
{return} bool
Source Code: /framework/classes/modules/asset/Asset.class.php#99 (show)
protected function Add($sFile$aParams$sType$bPrepend false$bReplace false)
{
    if (!
$this->CheckAssetType($sType)) {
        return 
false;
    }
    
$aParams['file'] = $sFile;
    
/**
     * Подготавливаем параметры
     */
    
$aParams $this->PrepareParams($aParams);
    
/**
     * В качестве уникального ключа использется имя или путь до файла
     */
    
$sFileKey $aParams['name'] ? $aParams['name'] : $aParams['file'];
    
/**
     * Проверям на необходимость замены
     */
    
if (isset($this->aAssets[$sType]['prepend'][$sFileKey])) {
        if (
$bReplace) {
            unset(
$this->aAssets[$sType]['prepend'][$sFileKey]);
        } else {
            return 
false;
        }
    }
    if (isset(
$this->aAssets[$sType]['append'][$sFileKey])) {
        if (
$bReplace) {
            unset(
$this->aAssets[$sType]['append'][$sFileKey]);
        } else {
            return 
false;
        }
    }
    
$this->aAssets[$sType][$bPrepend 'prepend' 'append'][$sFileKey] = $aParams;
    return 
true;
}

Добавляет новый файл

AddCss() method
public bool AddCss(string $sFile, array $aParams, bool $bPrepend=false, bool $bReplace=false)
$sFile string Полный путь до файла
$aParams array Дополнительные параметры
$bPrepend bool Добавлять файл в начало общего списка или нет
$bReplace bool Если такой файл уже добавлен, то заменяет его
{return} bool
Source Code: /framework/classes/modules/asset/Asset.class.php#144 (show)
public function AddCss($sFile$aParams$bPrepend false$bReplace false)
{
    return 
$this->Add($sFile$aParamsself::ASSET_TYPE_CSS$bPrepend$bReplace);
}

Добавляет файл css стиля

AddJs() method
public bool AddJs(string $sFile, array $aParams, bool $bPrepend=false, bool $bReplace=false)
$sFile string Полный путь до файла
$aParams array Дополнительные параметры
$bPrepend bool Добавлять файл в начало общего списка или нет
$bReplace bool Если такой файл уже добавлен, то заменяет его
{return} bool
Source Code: /framework/classes/modules/asset/Asset.class.php#159 (show)
public function AddJs($sFile$aParams$bPrepend false$bReplace false)
{
    return 
$this->Add($sFile$aParamsself::ASSET_TYPE_JS$bPrepend$bReplace);
}

Добавляет файл js скрипта

BuildHeadItems() method
public array BuildHeadItems()
{return} array Список HTML оберток подключения файлов
Source Code: /framework/classes/modules/asset/Asset.class.php#282 (show)
public function BuildHeadItems()
{
    
/**
     * Запускаем обработку
     */
    
$aAssets $this->Processing();

    
$aHeader array_combine(array_keys($this->aAssets), array(''''));
    foreach (
$aAssets as $sType => $aFile) {
        if (
$oType $this->CreateObjectType($sType)) {
            foreach (
$aFile as $aParams) {
                
$aHeader[$sType] .= $oType->getHeadHtml($aParams['file'], $aParams) . PHP_EOL;
            }
        }
    }
    return 
$aHeader;
}

Возвращает HTML код подключения файлов в HEAD'ер страницы

CheckAssetType() method
public bool CheckAssetType($sType $sType)
$sType $sType
{return} bool
Source Code: /framework/classes/modules/asset/Asset.class.php#171 (show)
public function CheckAssetType($sType)
{
    return 
in_array($sType, array(self::ASSET_TYPE_CSSself::ASSET_TYPE_JS));
}

Проверяет корректность типа файла

CreateObjectType() method
public bool|ModuleAsset_EntityType CreateObjectType(string $sType)
$sType string
{return} bool|ModuleAsset_EntityType
Source Code: /framework/classes/modules/asset/Asset.class.php#498 (show)
public function CreateObjectType($sType)
{
    
/**
     * Формируем имя класса для типа
     */
    
$sClass "ModuleAsset_EntityType" func_camelize($sType);
    if (
class_exists(Engine::GetEntityClass($sClass))) {
        return 
Engine::GetEntity($sClass);
    }
    return 
false;
}

Создает и возврашает объект типа

GetFileWeb() method
public string GetFileWeb(string $sFile, array $aParams=array ( ))
$sFile string Исходный путь до файла, обычно он задается в конфиге при подключении css/js, либо через методы Asset_Add*
$aParams array
{return} string
Source Code: /framework/classes/modules/asset/Asset.class.php#208 (show)
public function GetFileWeb($sFile$aParams = array())
{
    return 
$this->NormalizeFilePath($sFile$aParams);
}

Возвращает корректный WEB путь до файла

GetRealpath() method
public void GetRealpath($sPath)
$sPath
Source Code: /framework/classes/modules/asset/Asset.class.php#510 (show)
public function GetRealpath($sPath)
{
    if (
preg_match("@^(http|https):@"$sPath)) {
        
$aUrl parse_url($sPath);
        
$sPath $aUrl['path'];

        
$aParts = array();
        
$sPath preg_replace('~/\./~''/'$sPath);
        foreach (
explode('/'preg_replace('~/+~''/'$sPath)) as $sPart) {
            if (
$sPart === "..") {
                
array_pop($aParts);
            } elseif (
$sPart != "") {
                
$aParts[] = $sPart;
            }
        }
        return ((
array_key_exists('scheme',
            
$aUrl)) ? $aUrl['scheme'] . '://' $aUrl['host'] : "") . "/" implode("/"$aParts);
    } else {
        return 
realpath($sPath);
    }
}

Init() method
public void Init()
Source Code: /framework/classes/modules/asset/Asset.class.php#56 (show)
public function Init()
{
    
/**
     * Задаем начальную структуру для хранения списка файлов по типам
     */
    
$this->InitAssets();
}

Инициалищация модуля

InitAssets() method
protected void InitAssets()
Source Code: /framework/classes/modules/asset/Asset.class.php#67 (show)
protected function InitAssets()
{
    
$this->aAssets = array(
        
self::ASSET_TYPE_CSS => array(
            
/**
             * Список файлов для добавления в конец списка
             * В качестве ключей используется путь до файла либо уникальное имя, в качестве значений - дополнительные параметры
             */
            
'append'  => array(),
            
/**
             * Список файлов для добавления в начало списка
             */
            
'prepend' => array(),
        ),
        
self::ASSET_TYPE_JS  => array(
            
'append'  => array(),
            
'prepend' => array(),
        ),
    );
}

Задает начальную структуры для хранения списка файлов по типам

IsLockMerge() method
protected bool IsLockMerge()
{return} bool
Source Code: /framework/classes/modules/asset/Asset.class.php#404 (show)
protected function IsLockMerge()
{
    
$sFile Config::Get('path.tmp.server') . '/asset.merge.lock';
    
$this->hDescriptorMergeLock = @fopen($sFile'a');
    return 
$this->Fs_IsLock($this->hDescriptorMergeLock);
}

Проверяет на блокировку Если нет блокировки, то создает ее

Merge() method
protected string Merge($aAssetItems $aAssetItems, $sType $sType, bool $bCompress=false)
$aAssetItems $aAssetItems
$sType $sType
$bCompress bool
{return} string Web путь до нового файла
Source Code: /framework/classes/modules/asset/Asset.class.php#431 (show)
protected function Merge($aAssetItems$sType$bCompress false)
{
    
$sCacheDir Config::Get('path.cache_assets.server') . "/" Config::Get('view.skin');
    
$sCacheFile $sCacheDir "/" md5(serialize(array_keys($aAssetItems)) . '_head') . '.' $sType;
    
/**
     * Если файла еще нет, то создаем его
     * Но только в том случае, если еще другой процесс не начал его создавать - проверка на блокировку
     */
    
if (!file_exists($sCacheFile) and !$this->IsLockMerge()) {
        
/**
         * Создаем директорию для кеша текущего скина,
         * если таковая отсутствует
         */
        
if (!is_dir($sCacheDir)) {
            @
mkdir($sCacheDir0777true);
        }
        
$sContent '';
        foreach (
$aAssetItems as $sFile => $aParams) {
            if (
strpos($sFile'//') === 0) {
                
/**
                 * Добавляем текущий протокол
                 */
                
$sFile = (Router::GetIsSecureConnection() ? 'https' 'http') . ':' $sFile;
            }
            
$sFile $this->Fs_GetPathServerFromWeb($sFile);
            
/**
             * Считываем содержимое файла
             */
            
if ($sFileContent = @file_get_contents($sFile)) {
                
/**
                 * Создаем объект
                 */
                
if ($oType $this->CreateObjectType($sType)) {
                    
$oType->setContent($sFileContent);
                    
$oType->setFile($sFile);
                    unset(
$sFileContent);
                    
$oType->prepare();
                    if (
$bCompress and (!isset($aParams['compress']) or $aParams['compress'])) {
                        
$oType->compress();
                    }
                    
$sContent .= $oType->getContent();
                    unset(
$oType);
                } else {
                    
$sContent .= $sFileContent;
                }
            }
        }
        
/**
         * Создаем файл и сливаем туда содержимое
         */
        
@file_put_contents($sCacheFile$sContent);
        @
chmod($sCacheFile0766);
        
/**
         * Удаляем блокировку
         */
        
$this->RemoveLockMerge();
    }
    return 
$this->Fs_GetPathWebFromServer($sCacheFile);
}

Производит объединение и сжатие файлов

NormalizeFilePath() method
protected string NormalizeFilePath($sFile $sFile, array $aParams=array ( ))
$sFile $sFile
$aParams array
{return} string
Source Code: /framework/classes/modules/asset/Asset.class.php#221 (show)
protected function NormalizeFilePath($sFile$aParams = array())
{
    
/**
     * По дефолту считаем, что это локальный абсолютный путь до файла: /var/www/site.com  или c:\server\root\site.com
     */
    
$sProtocol '';
    
$sPath $sFile;
    
$sSeparate DIRECTORY_SEPARATOR;
    
/**
     * Проверяем на URL https://site.com или http://site.com
     */
    
if (preg_match('#^(https?://)(.*)#i'$sFile$aMatch)) {
        
$sProtocol $aMatch[1];
        
$sPath $aMatch[2];
        
$sSeparate '/';
        
/**
         * Если необходимо, то меняем протокол на https
         */
        
if (Router::GetIsSecureConnection() and strtolower($sProtocol) == 'http://' and Config::Get('module.asset.force_https')) {
            
$sProtocol 'https://';
        }
        
/**
         * Проверяем на //site.com
         */
    
} elseif (strpos($sFile'//') === 0) {
        
$sProtocol '//';
        
$sPath substr($sFile2);
        
$sSeparate '/';
        
/**
         * Проверяем на относительный путь без протокола и без первого слеша
         */
    
} elseif (preg_match('#^[a-z0-9\_]#i'$sFile)) {
        
/**
         * Считаем, что указывался путь относительно корня текущего шаблона
         */
        
$sSeparate '/';
        if (isset(
$aParams['plugin']) and $aParams['plugin']) {
            
/**
             * Относительно шаблона плагина
             */
            
$sPath Plugin::GetTemplateWebPath($aParams['plugin']) . $sFile;
        } else {
            
$sPath Router::GetFixPathWeb(Config::Get('path.skin.web')) . $sSeparate $sFile;
        }
        return 
$sPath;
    }
    
/**
     * Могут встречаться двойные слеши, поэтому делаем замену
     */
    
$sPath preg_replace("#([\\\/])+#"$sSeparate$sPath);
    
/**
     * Возвращаем результат
     */
    
return $sProtocol $sPath;
}

Приводит путь до файла к единому виду

PrepareParams() method
public array PrepareParams($aParams $aParams)
$aParams $aParams
{return} array
Source Code: /framework/classes/modules/asset/Asset.class.php#183 (show)
public function PrepareParams($aParams)
{
    
$aResult = array();

    
$aResult['merge'] = (isset($aParams['merge']) and !$aParams['merge']) ? false true;
    
$aResult['compress'] = (isset($aParams['compress']) and !$aParams['compress']) ? false true;
    
$aResult['browser'] = (isset($aParams['browser']) and $aParams['browser']) ? $aParams['browser'] : null;
    
$aResult['plugin'] = (isset($aParams['plugin']) and $aParams['plugin']) ? $aParams['plugin'] : null;
    
$aResult['name'] = (isset($aParams['name']) and $aParams['name']) ? strtolower($aParams['name']) : null;
    if (isset(
$aParams['file'])) {
        
$aResult['file'] = $this->GetFileWeb($aParams['file'], $aParams);
    } else {
        
$aResult['file'] = null;
    }
    return 
$aResult;
}

Производит предварительную обработку параметров

Processing() method
public array Processing()
{return} array Возвращает список результирующих файлов вида array( 'css'=>array( 'name'=>$aParams, ... ), ... )
Source Code: /framework/classes/modules/asset/Asset.class.php#305 (show)
public function Processing()
{
    
$aTypes array_keys($this->aAssets);
    
$aFilesMain $aResult array_combine($aTypesarray_pad(array(), count($aTypes), array()));
    
/**
     * Сначала добавляем файлы из конфига
     */
    
$aConfigAssets = (array)Config::Get('head.default');
    foreach (
$aConfigAssets as $sType => $aAssets) {
        if (!
$this->CheckAssetType($sType)) {
            continue;
        }
        
/**
         * Перебираем файлы
         */
        
foreach ($aAssets as $sFile => $aParams) {
            if (
is_numeric($sFile)) {
                
$sFile $aParams;
                
$aParams = array();
            }
            
$aParams['file'] = $sFile;
            
/**
             * Подготавливаем параметры
             */
            
$aParams $this->PrepareParams($aParams);
            
/**
             * В качестве уникального ключа использется имя или путь до файла
             */
            
$sFileKey $aParams['name'] ? $aParams['name'] : $aParams['file'];
            
$aFilesMain[$sType][$sFileKey] = $aParams;
        }
    }

    foreach (
$aTypes as $sType) {
        
/**
         * Объединяем списки
         */
        
$aFilesMain[$sType] = array_merge(
            
$this->aAssets[$sType]['prepend'],
            
$aFilesMain[$sType],
            
$this->aAssets[$sType]['append']
        );
        
/**
         * Выделяем файлы для конкретных браузеров
         */
        
$aFilesBrowser array_filter(
            
$aFilesMain[$sType],
            function (
$aParams) {
                return 
$aParams['browser'] ? true false;
            }
        );
        
/**
         * Исключаем файлы из основного списка
         */
        
$aFilesMain[$sType] = array_diff_key($aFilesMain[$sType], $aFilesBrowser);
        
/**
         * Если необходимо сливать файлы, то выделяем исключения
         */
        
$aFilesNoMerge = array();
        if (
Config::Get("module.asset.{$sType}.merge")) {
            
$aFilesNoMerge array_filter(
                
$aFilesMain[$sType],
                function (
$aParams) {
                    return !
$aParams['merge'];
                }
            );
            
/**
             * Исключаем файлы из основного списка
             */
            
$aFilesMain[$sType] = array_diff_key($aFilesMain[$sType], $aFilesNoMerge);
        }
        
/**
         * Обрабатываем основной список
         */
        
if (Config::Get("module.asset.{$sType}.merge")) {
            
$sFilePath $this->Merge($aFilesMain[$sType], $sType,
                (bool)
Config::Get("module.asset.{$sType}.compress"));
            
$aResult[$sType][$sFilePath] = array('file' => $sFilePath);
        } else {
            
$aResult[$sType] = array_merge($aResult[$sType], $aFilesMain[$sType]);
        }
        
/**
         * Обрабатываем список исключения объединения
         */
        
$aResult[$sType] = array_merge($aResult[$sType], $aFilesNoMerge);
        
/**
         * Обрабатываем список для отдельных браузеров
         */
        
$aResult[$sType] = array_merge($aResult[$sType], $aFilesBrowser);
    }
    return 
$aResult;
}

Производит обработку файлов

RemoveLockMerge() method
protected void RemoveLockMerge()
Source Code: /framework/classes/modules/asset/Asset.class.php#414 (show)
protected function RemoveLockMerge()
{
    if (
$this->hDescriptorMergeLock) {
        
$this->Fs_RemoveLock($this->hDescriptorMergeLock);
        
$this->hDescriptorMergeLock null;
    }
}

Удаляет блокировку

Shutdown() method
public void Shutdown()
Source Code: /framework/classes/modules/asset/Asset.class.php#532 (show)
public function Shutdown()
{
    
/**
     * Удаляем блокировку
     */
    
$this->RemoveLockMerge();
}