/** * Adds support for pipeline assets. * * {@inheritdoc} */ protected function parseInput($input, array $options = array()) { if (is_string($input) && '|' == $input[0]) { switch (pathinfo($options['output'], PATHINFO_EXTENSION)) { case 'js': $type = 'js'; break; case 'css': $type = 'css'; break; default: throw new \RuntimeException('Unsupported pipeline asset type provided: ' . $input); } $assets = new AssetCollection(); foreach ($this->locator->locatePipelinedAssets(substr($input, 1), $type) as $formula) { $filters = array(); if ($formula['filter']) { $filters[] = $this->getFilter($formula['filter']); } $asset = new FileAsset($formula['root'] . '/' . $formula['file'], $filters, $options['root'][0], $formula['file']); $asset->setTargetPath($formula['file']); $assets->add($asset); } return $assets; } return parent::parseInput($input, $options); }
public function testAssetLastModifiedTimestampIsPrependBeforeFileExtension() { $asset = new FileAsset(TEST_ASSETS_DIR . '/css/global.css'); $asset->setTargetPath(TEST_PUBLIC_DIR . '/css/global.css'); $this->cacheBuster->process($asset); $this->assertSame(TEST_PUBLIC_DIR . '/css/global.' . $asset->getLastModified() . '.css', $asset->getTargetPath()); }
/** * {@inheritdoc} */ public function process() { $filters = new FilterCollection(array(new CssRewriteFilter())); $assets = new AssetCollection(); $styles = $this->packageStyles($this->packages); foreach ($styles as $package => $packageStyles) { foreach ($packageStyles as $style => $paths) { foreach ($paths as $path) { // The full path to the CSS file. $assetPath = realpath($path); // The root of the CSS file. $sourceRoot = dirname($path); // The style path to the CSS file when external. $sourcePath = $package . '/' . $style; // Where the final CSS will be generated. $targetPath = $this->componentDir; // Build the asset and add it to the collection. $asset = new FileAsset($assetPath, $filters, $sourceRoot, $sourcePath); $asset->setTargetPath($targetPath); $assets->add($asset); } } } $css = $assets->dump(); if (file_put_contents($this->componentDir . '/require.css', $css) === FALSE) { $this->io->write('<error>Error writing require.css to destination</error>'); return false; } }
protected function createAssetManager() { $asset = new FileAsset(__DIR__ . '/../../../tests/test.css'); $asset->setTargetPath('css/test.css'); $assetManager = new AssetManager(); $assetManager->set('test_css', $asset); return $assetManager; }
public function filterLoad(AssetInterface $asset) { $importFilter = $this->importFilter; $sourceRoot = $asset->getSourceRoot(); $sourcePath = $asset->getSourcePath(); $callback = function ($matches) use($importFilter, $sourceRoot, $sourcePath) { if (!$matches['url']) { return $matches[0]; } if (null === $sourceRoot) { return $matches[0]; } $importRoot = $sourceRoot; if (false !== strpos($matches['url'], '://')) { // absolute list($importScheme, $tmp) = explode('://', $matches['url'], 2); list($importHost, $importPath) = explode('/', $tmp, 2); $importRoot = $importScheme . '://' . $importHost; } elseif (0 === strpos($matches['url'], '//')) { // protocol-relative list($importHost, $importPath) = explode('/', substr($matches['url'], 2), 2); $importHost = '//' . $importHost; } elseif ('/' == $matches['url'][0]) { // root-relative $importPath = substr($matches['url'], 1); } elseif (null !== $sourcePath) { // document-relative $importPath = $matches['url']; if ('.' != ($sourceDir = dirname($sourcePath))) { $importPath = $sourceDir . '/' . $importPath; } } else { return $matches[0]; } // ignore other imports if ('css' != pathinfo($importPath, PATHINFO_EXTENSION)) { return $matches[0]; } $importSource = $importRoot . '/' . $importPath; if (false !== strpos($importSource, '://') || 0 === strpos($importSource, '//')) { $import = new HttpAsset($importSource, array($importFilter), true); } elseif (!file_exists($importSource)) { // ignore not found imports return $matches[0]; } else { $import = new FileAsset($importSource, array($importFilter), $importRoot, $importPath); } $import->setTargetPath($sourcePath); return $import->dump(); }; $content = $asset->getContent(); $lastHash = md5($content); do { $content = $this->filterImports($content, $callback); $hash = md5($content); } while ($lastHash != $hash && ($lastHash = $hash)); $asset->setContent($content); }
/** * {@inheritdoc} */ public function process() { $filters = array(new CssRewriteFilter()); if ($this->config->has('component-styleFilters')) { $customFilters = $this->config->get('component-styleFilters'); if (isset($customFilters) && is_array($customFilters)) { foreach ($customFilters as $filter => $filterParams) { $reflection = new \ReflectionClass($filter); $filters[] = $reflection->newInstanceArgs($filterParams); } } } $filterCollection = new FilterCollection($filters); $assets = new AssetCollection(); $styles = $this->packageStyles($this->packages); foreach ($styles as $package => $packageStyles) { $packageAssets = new AssetCollection(); $packagePath = $this->componentDir . '/' . $package; foreach ($packageStyles as $style => $paths) { foreach ($paths as $path) { // The full path to the CSS file. $assetPath = realpath($path); // The root of the CSS file. $sourceRoot = dirname($path); // The style path to the CSS file when external. $sourcePath = $package . '/' . $style; //Replace glob patterns with filenames. $filename = basename($style); if (preg_match('~^\\*(\\.[^\\.]+)$~', $filename, $matches)) { $sourcePath = str_replace($filename, basename($assetPath), $sourcePath); } // Where the final CSS will be generated. $targetPath = $this->componentDir; // Build the asset and add it to the collection. $asset = new FileAsset($assetPath, $filterCollection, $sourceRoot, $sourcePath); $asset->setTargetPath($targetPath); $assets->add($asset); // Add asset to package collection. $sourcePath = preg_replace('{^.*' . preg_quote($package) . '/}', '', $sourcePath); $asset = new FileAsset($assetPath, $filterCollection, $sourceRoot, $sourcePath); $asset->setTargetPath($packagePath); $packageAssets->add($asset); } } if (file_put_contents($packagePath . '/' . $package . '-built.css', $packageAssets->dump()) === FALSE) { $this->io->write("<error>Error writing {$package}-built.css to destination</error>"); } } if (file_put_contents($this->componentDir . '/require.css', $assets->dump()) === FALSE) { $this->io->write('<error>Error writing require.css to destination</error>'); return false; } return null; }
public function testAssetWithInputVars() { $asset = new FileAsset(__DIR__ . '/Fixture/messages.{locale}.js', array(), null, null, array('locale')); $asset->setTargetPath('messages.{locale}.js'); $this->writer->writeAsset($asset); $this->assertFileExists($this->dir . '/messages.en.js'); $this->assertFileExists($this->dir . '/messages.de.js'); $this->assertFileExists($this->dir . '/messages.fr.js'); $this->assertEquals('var messages = {"text.greeting": "Hello %name%!"};', file_get_contents($this->dir . '/messages.en.js')); $this->assertEquals('var messages = {"text.greeting": "Hallo %name%!"};', file_get_contents($this->dir . '/messages.de.js')); $this->assertEquals('var messages = {"text.greet": "All\\u00f4 %name%!"};', file_get_contents($this->dir . '/messages.fr.js')); }
/** * @return \Assetic\AssetManager */ protected function createAssetManager() { $manager = new \Assetic\AssetManager(); $localeInfo = $this->getLocaleInfo(); foreach ($localeInfo as $lang => $countries) { $manager->set('locale_' . $lang, $asset = new FileAsset(dirname(dirname(__DIR__)) . '/Resources/public/images/' . $lang . '.png')); $asset->setTargetPath('images/locale/' . $lang . '.png'); foreach ($countries as $country) { $manager->set('locale_' . $lang . '_' . strtolower($country), $asset = new FileAsset(dirname(dirname(__DIR__)) . '/Resources/public/images/' . $lang . '-' . $country . '.png')); $asset->setTargetPath('images/locale/' . $lang . '-' . $country . '.png'); } } return $manager; }
public function collectFrameworkStylesheets(CollectAssetsEvent $event, $eventName, EventDispatcherInterface $eventDispatcher) { if (is_array($GLOBALS['TL_FRAMEWORK_CSS']) && !empty($GLOBALS['TL_FRAMEWORK_CSS'])) { foreach (array_unique($GLOBALS['TL_FRAMEWORK_CSS']) as $stylesheet) { $stripStaticDomainEvent = new StripStaticDomainEvent($event->getRenderMode(), $event->getPage(), $event->getLayout(), $stylesheet); $eventDispatcher->dispatch(ThemePlusEvents::STRIP_STATIC_DOMAIN, $stripStaticDomainEvent); $stylesheet = $stripStaticDomainEvent->getUrl(); $asset = new FileAsset(TL_ROOT . DIRECTORY_SEPARATOR . $stylesheet, [new CssRewriteFilter()], TL_ROOT, $stylesheet); $generateAssetPathEvent = new GenerateAssetPathEvent($event->getRenderMode(), $event->getPage(), $event->getLayout(), $asset, $event->getDefaultFilters(), 'css'); $eventDispatcher->dispatch(ThemePlusEvents::GENERATE_ASSET_PATH, $generateAssetPathEvent); $asset->setTargetPath($generateAssetPathEvent->getPath()); $event->append($asset, -50); } $GLOBALS['TL_FRAMEWORK_CSS'] = []; } }
public function cssPackAction() { $collection = new AssetCollection(); foreach ($this->container->getParameter('cms.cms_resources.css_pack') as $asset) { $assetPath = $this->container->getApplication()->getWebRoot() . DIRECTORY_SEPARATOR . $asset; $assetObject = new FileAsset($assetPath, array(), $this->container->getApplication()->getWebRoot()); $assetObject->setTargetPath('/_cms_internal/'); if (substr($asset, strrpos($asset, '.')) == '.less') { $assetObject->ensureFilter(new LessphpFilter()); } $collection->add($assetObject); } $content = $this->container->getCache()->fetch('cms_assets', 'css_pack', function () use($collection) { return $collection->dump(new CssRewriteFilter()); }, $collection->getLastModified()); return new Response($content, 200, array('Content-Type' => 'text/css')); }
/** * @dataProvider getFilters */ public function testImport($filter1, $filter2) { $asset = new FileAsset(__DIR__ . '/fixtures/cssimport/main.css', array(), __DIR__ . '/fixtures/cssimport', 'main.css'); $asset->setTargetPath('foo/bar.css'); $asset->ensureFilter($filter1); $asset->ensureFilter($filter2); $expected = <<<CSS /* main.css */ /* import.css */ body { color: red; } /* more/evenmore/deep1.css */ /* more/evenmore/deep2.css */ body { background: url(../more/evenmore/bg.gif); } body { color: black; } CSS; $this->assertEquals($expected, $asset->dump(), '->filterLoad() inlines CSS imports'); }
/** * Dump all assets */ public function all() { foreach ($this->getAssetsXMLFiles() as $path => $XMLFile) { $this->out(''); $this->out(sprintf('<info>Start dumping "%s" assets:</info>', $path)); $xml = new Xml(); $domDocument = $xml->build($XMLFile, ['return' => 'domdocument']); $xpath = new DOMXPath($domDocument); $assetsNodeList = $xpath->query('/assetic/assets/asset'); $assetManager = new AssetManager(); /** @var $assetNode DOMElement */ foreach ($assetsNodeList as $assetNode) { $source = strtr($assetNode->getElementsByTagName('source')->item(0)->nodeValue, $this->paths); $destination = strtr($assetNode->getElementsByTagName('destination')->item(0)->nodeValue, $this->paths); $assetManager->set($assetNode->getAttribute('name'), $fileAsset = new FileAsset($source)); $fileAsset->setTargetPath($destination); $this->out($source . ' <info> >>> </info> ' . WWW_ROOT . $destination); } $assetWriter = new AssetWriter(WWW_ROOT); $assetWriter->writeManagerAssets($assetManager); $this->dumpStaticFiles($domDocument); $this->out('<info>End</info>'); } }
} if (APP_WEB_SITE_DIR) { $writer = new AssetWriter(APP_WEB_SITE_DIR . '/theme/default/img/'); $writer->writeManagerAssets($am); } if (APP_WEB_SINGLE_SITE_DIR) { $writer = new AssetWriter(APP_WEB_SINGLE_SITE_DIR . '/theme/default/img/'); $writer->writeManagerAssets($am); } } # Sysadmin if (APP_WEB_SYSADMIN_DIR || APP_WEB_SINGLE_SITE_DIR || APP_WEB_INDEX_DIR) { $am = new AssetManager(); foreach ($imgFiles['sysadmin'] as $nameonly => $filename) { $fa = new FileAsset($filename, $imgFilters); $fa->setTargetPath($nameonly); $am->set(str_replace('.', '_', $nameonly), $fa); } if (APP_WEB_SYSADMIN_DIR) { $writer = new AssetWriter(APP_WEB_SYSADMIN_DIR . '/theme/default/imgsysadmin/'); $writer->writeManagerAssets($am); } if (APP_WEB_SINGLE_SITE_DIR) { $writer = new AssetWriter(APP_WEB_SINGLE_SITE_DIR . '/theme/default/imgsysadmin/'); $writer->writeManagerAssets($am); } if (APP_WEB_INDEX_DIR) { $writer = new AssetWriter(APP_WEB_INDEX_DIR . '/theme/default/imgsysadmin/'); $writer->writeManagerAssets($am); } }
/** * @param string $filename * @return FileAsset */ private function getFileAsset($filename) { $asset = new FileAsset($this->getAssetPath() . $filename); $asset->setTargetPath($filename); return $asset; }
/** * 合并文件,并且返回合并之后的文件名 * * @param string $moduleUniqueId * @param array $fileRelativePathArray * @param string $fileExt 合并之后的文件扩展名 * @param callback $fileContentFilter 对每个文件的内容做 filter * * @return string 合并之后的文件名 */ private function mergeAssetCssJsFile($moduleUniqueId, array $fileRelativePathArray, $fileExt, $fileContentFilter = null) { if (empty($fileRelativePathArray)) { throw new \InvalidArgumentException('fileRelativePathArray can not be empty'); } $targetModuleBasePath = $this->assetBasePath . DIRECTORY_SEPARATOR . $this->getModulePublishRelativeDir($moduleUniqueId) . DIRECTORY_SEPARATOR; // 计算合并之后的文件名 $targetFileNameSource = ''; foreach ($fileRelativePathArray as $relativeAssetPath) { // 智能发布资源 $this->publishAsset($moduleUniqueId, $relativeAssetPath); $sourcePath = $targetModuleBasePath . $relativeAssetPath; if (!is_file($sourcePath)) { printLog('Calculate FileNameSource Error : [' . $sourcePath . '] is not a regular file', 'AssetManager', \Core\Log\Base::ERROR); continue; } $targetModifyTime = filemtime($sourcePath); $targetFileNameSource .= '{' . $sourcePath . '[' . $targetModifyTime . ']}'; } // 目标文件名 $targetFileNameSourceMd5 = md5($targetFileNameSource); $targetFileName = $targetFileNameSourceMd5 . '.min' . $fileExt; // 合并文件已经存在,直接退出就可以了 if (is_file($targetModuleBasePath . $targetFileName)) { goto out; } // 打印 log printLog($targetFileNameSource, 'AssetManager'); // 做文件的合并 $filterArray = array(); // 建立对应的 filter if ('.js' == $fileExt) { $filterArray = array(new JSMinFilter()); } elseif ('.css' == $fileExt) { $filterArray = array(new CssImportFilter(), new CssRewriteFilter(), new CssMinFilter()); } else { // do nothing } $mergeFileContent = ''; foreach ($fileRelativePathArray as $relativeAssetPath) { $sourcePath = $targetModuleBasePath . $relativeAssetPath; if (!is_file($sourcePath)) { printLog('Merge File Error : [' . $sourcePath . '] is not a regular file', 'AssetManager', \Core\Log\Base::ERROR); continue; } // 我们采用 Assetic 来做文件处理 $fileAsset = new FileAsset($targetModuleBasePath . $relativeAssetPath, $filterArray, $targetModuleBasePath, $relativeAssetPath); $fileAsset->setTargetPath('.'); $mergeFileContent .= $fileContentFilter ? call_user_func_array($fileContentFilter, array($relativeAssetPath, $fileAsset->dump())) : $fileAsset->dump(); unset($fileAsset); // 释放内存 } // 生成合并之后的文件 file_put_contents($targetModuleBasePath . $targetFileName, $mergeFileContent); out: return $targetFileName; }
public function testWriteAssetIfNotUpdated() { $this->configuration->setBuildOnRequest(true); $this->configuration->setWriteIfChanged(true); $this->object->build(); $manager = $this->object->getAssetManager(); $assets = $manager->get('base_css')->all(); /** @var \Assetic\Asset\AssetInterface $asset */ $asset = $assets[0]; $asset->setTargetPath($manager->get('base_css')->getTargetPath()); $targetFile = $this->configuration->getWebPath($asset->getTargetPath()); if (is_file($targetFile)) { unlink($targetFile); } $this->assertFileNotExists($targetFile); $this->object->writeAsset($asset); $this->assertFileExists($targetFile); $sourceFile = $asset->getSourceRoot() . '/' . $asset->getSourcePath(); $targetMTime = filemtime($targetFile); sleep(2); $modifiedAsset = new FileAsset($sourceFile); $modifiedAsset->setTargetPath($targetFile); $this->object->writeAsset($modifiedAsset); clearstatcache(true, $targetFile); $targetMTimeNotModified = filemtime($targetFile); $this->assertLessThanOrEqual($targetMTime, $targetMTimeNotModified); }
protected function addStyleSheets($objPage, $objLayout, array $files, $path, $useSass, array $filters) { /** @var RenderModeDeterminer $renderModeDeterminer */ $renderModeDeterminer = $GLOBALS['container']['theme-plus-render-mode-determiner']; $renderMode = $renderModeDeterminer->determineMode(); /** @var AsseticFactory $asseticFactory */ $asseticFactory = $GLOBALS['container']['assetic.factory']; // default filter $defaultFilters = $asseticFactory->createFilterOrChain($objLayout->asseticStylesheetFilter, RenderMode::DESIGN == $renderMode); /** @var EventDispatcherInterface $eventDispatcher */ $eventDispatcher = $GLOBALS['container']['event-dispatcher']; foreach ($files as $file) { if ($useSass) { $file = $this->transformCssToSass($file); } $file = $path . '/' . $file; $asset = new FileAsset(TL_ROOT . '/' . $file, $filters, TL_ROOT, $file); $generateAssetPathEvent = new GenerateAssetPathEvent($renderMode, $objPage, $objLayout, $asset, $defaultFilters, 'css'); $eventDispatcher->dispatch(ThemePlusEvents::GENERATE_ASSET_PATH, $generateAssetPathEvent); $asset->setTargetPath($generateAssetPathEvent->getPath()); array_unshift($GLOBALS['TL_CSS'], $asset); } }