├── .gitignore ├── .travis.yml ├── MIT-LICENSE ├── README.md ├── composer.json ├── doc └── assetic.md ├── example ├── assetic.php └── assetic │ └── resources │ └── css │ ├── 1.css │ └── 2.css ├── phpunit.xml.dist ├── src └── SilexAssetic │ ├── Assetic │ └── Dumper.php │ └── AsseticServiceProvider.php └── tests ├── SilexAssetic └── Tests │ └── AsseticServiceProviderTest.php └── bootstrap.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.phar 3 | composer.lock 4 | example/assetic/output/* 5 | example/assetic/cache/* 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | before_script: composer install --dev --prefer-source 4 | 5 | php: 6 | - 5.3 7 | - 5.4 8 | - 5.5 9 | 10 | matrix: 11 | allow_failures: 12 | - php: 5.5 13 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Sven Eisenschmidt 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Silex-Assetic 2 | ================ 3 | 4 | [![Build Status](https://secure.travis-ci.org/mheap/Silex-Assetic.png?branch=master)](http://travis-ci.org/mheap/Silex-Assetic) 5 | 6 | Installation 7 | ------------ 8 | 9 | Create a composer.json in your projects root-directory:: 10 | 11 | { 12 | "require": { 13 | "mheap/Silex-Assetic": "*" 14 | } 15 | } 16 | 17 | and run:: 18 | 19 | curl -s http://getcomposer.org/installer | php 20 | php composer.phar install 21 | 22 | 23 | More Information 24 | ---------------- 25 | 26 | Read the documentation files under */doc*. 27 | 28 | License 29 | ------- 30 | 31 | 'Silex-Assetic' is licensed under the MIT license. 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mheap/silex-assetic", 3 | "description": "Assetic extension for Silex", 4 | "keywords": ["silex", "assetic"], 5 | "homepage": "https://github.com/mheap/Silex-Assetic", 6 | "type": "library", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Sven Eisenschmidt", 11 | "email": "sven.eisenschmidt@gmail.com", 12 | "homepage": "http://unsicherheitsagent.de/" 13 | }, 14 | { 15 | "name": "Michael Heap", 16 | "email": "m@michaelheap.com", 17 | "homepage": "http://michaelheap.com/" 18 | } 19 | ], 20 | "require": { 21 | "php": ">=5.3.0", 22 | "kriswallsmith/assetic": "~1.0", 23 | "symfony/finder": "~2.4" 24 | }, 25 | "require-dev": { 26 | "silex/silex": "~2.0@dev", 27 | "twig/twig": "~1.2", 28 | "phpunit/phpunit": "~3.7.10" 29 | }, 30 | "suggest": { 31 | "twig/twig": "~1.2" 32 | }, 33 | "autoload": { 34 | "psr-0": { 35 | "SilexAssetic": "src" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /doc/assetic.md: -------------------------------------------------------------------------------- 1 | AsseticServiceProvider 2 | ====================== 3 | 4 | The *AsseticServiceProvider* provides powerful asset management through Kris Wallsmith's [Assetic](https://github.com/kriswallsmith/assetic) library. 5 | 6 | Parameters 7 | ---------- 8 | 9 | * ```assetic.path_to_web```: Location where to dump all generated files. 10 | * ```assetic.options```: An associative array of assetic options. 11 | * ```assetic.options => debug``` (defaults to false, optional): 12 | * ```assetic.options => formulae_cache_dir``` (optional): When ```formulae_cache_dir``` is set, Assetic will cache assets generated trough formulae in this folder to improve performance. Remember, assets added trough the AssetManager need to care about their own cache. 13 | * ```assetic.options => auto_dump_assets``` (defaults to true,optional): Whether to write all the assets to filesystem on every request. 14 | 15 | Services 16 | -------- 17 | 18 | * ```assetic```: Instance of AssetFactory for holding filters and assets (not formulae). 19 | * ```assetic.asset_manager```: Instance of AssetManager for adding assets (implements AssetInterface). 20 | 21 | Example usage: 22 | ```php 23 | set('extra_css', $asset); 26 | ``` 27 | * ```assetic.filter_manager```: Instance of FilterManager for adding filters (implements FilterInterface) 28 | 29 | Example usage: 30 | ```php 31 | set('css_min', $filter); 34 | ``` 35 | 36 | * ```assetic.asset_writer```: If you need it, feel free to use 37 | * ```assetic.lazy_asset_manager```: Instance of LazyAssetManager to enable passing-in assets as formulae 38 | 39 | Example usage: 40 | ```php 41 | setFormula('extra_css', array( 43 | array(__DIR__ . '/extra/*.css'), 44 | array('yui_css'), 45 | array('output' => 'css/extra') 46 | )); 47 | ``` 48 | 49 | * ```assetic.dumper```: Instance of SilexAssetic\Assetic\Dumper. Contains methods to dump assets. 50 | 51 | Registering 52 | ----------- 53 | 54 | Example registration and configuration: 55 | 56 | ```php 57 | register(new SilexAssetic\AsseticServiceProvider()); 59 | 60 | $app['assetic.path_to_web'] = __DIR__ . '/assets'; 61 | $app['assetic.options'] = array( 62 | 'debug' => true, 63 | ); 64 | $app->extend('assetic.filter_manager', function($fm, $app) { 65 | $fm->set('yui_css', new Assetic\Filter\Yui\CssCompressorFilter( 66 | '/usr/share/yui-compressor/yui-compressor.jar' 67 | )); 68 | $fm->set('yui_js', new Assetic\Filter\Yui\JsCompressorFilter( 69 | '/usr/share/yui-compressor/yui-compressor.jar' 70 | )); 71 | 72 | return $fm; 73 | }); 74 | $app->extend('assetic.asset_manager', function($am, $app) { 75 | $am->set('styles', new Assetic\Asset\AssetCache( 76 | new Assetic\Asset\GlobAsset( 77 | __DIR__ . '/resources/css/*.css', 78 | array($app['assetic.filter_manager']->get('yui_css')) 79 | ), 80 | new Assetic\Cache\FilesystemCache(__DIR__ . '/cache/assetic') 81 | )); 82 | $am->get('styles')->setTargetPath('css/styles.css'); 83 | 84 | return $am; 85 | }); 86 | ``` 87 | -------------------------------------------------------------------------------- /example/assetic.php: -------------------------------------------------------------------------------- 1 | register(new Silex\Extension\TwigExtension()); 6 | 7 | $app['twig.path'] = __DIR__ . '/twig'; 8 | 9 | $app->register(new SilexAssetic\AsseticServiceProvider()); 10 | 11 | $app['assetic.path_to_web'] = __DIR__ . '/assetic/output'; 12 | $app['assetic.options'] = array( 13 | 'formulae_cache_dir' => __DIR__ . '/assetic/cache', 14 | 'debug' => false 15 | ); 16 | $app->extend('assetic.filter_manager', function($fm, $app) { 17 | $fm->set('yui_css', new Assetic\Filter\Yui\CssCompressorFilter( 18 | '/usr/share/yui-compressor/yui-compressor.jar' 19 | )); 20 | $fm->set('yui_js', new Assetic\Filter\Yui\JsCompressorFilter( 21 | '/usr/share/yui-compressor/yui-compressor.jar' 22 | )); 23 | 24 | return $fm; 25 | }; 26 | $app->extend('assetic.asset_manager', function($am, $app) { 27 | $am->set('styles', new Assetic\Asset\AssetCache( 28 | new Assetic\Asset\GlobAsset( 29 | __DIR__ . '/assetic/resources/css/*.css', 30 | array($fm->get('yui_css')) 31 | ), 32 | new Assetic\Cache\FilesystemCache(__DIR__ . '/assetic/cache') 33 | )); 34 | $am->get('styles')->setTargetPath('css/styles'); 35 | 36 | return $am; 37 | }); 38 | 39 | $app->get('/', function () use ($app) { 40 | return 'Hello!'; 41 | }); 42 | 43 | $app->run(); 44 | -------------------------------------------------------------------------------- /example/assetic/resources/css/1.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: red; 3 | } -------------------------------------------------------------------------------- /example/assetic/resources/css/2.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: black; 3 | } -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | ./tests/SilexAssetic/ 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/SilexAssetic/Assetic/Dumper.php: -------------------------------------------------------------------------------- 1 | am = $am; 46 | $this->lam = $lam; 47 | $this->writer = $writer; 48 | } 49 | 50 | /** 51 | * @param \Twig_Environment $twig 52 | * @param \Twig_Loader_Filesystem $loader 53 | */ 54 | public function setTwig(\Twig_Environment $twig, \Twig_Loader_Filesystem $loader) 55 | { 56 | $this->twig = $twig; 57 | $this->loader = $loader; 58 | } 59 | 60 | /** 61 | * Locates twig templates and adds their defined assets to the lazy asset manager 62 | */ 63 | public function addTwigAssets() 64 | { 65 | if (!$this->twig instanceof \Twig_Environment) { 66 | throw new \LogicException('Twig environment not set'); 67 | } 68 | 69 | $twigNamespaces = $this->loader->getNamespaces(); 70 | 71 | foreach ($twigNamespaces as $ns) { 72 | 73 | if ( count($this->loader->getPaths($ns)) > 0 ) { 74 | $iterator = Finder::create()->files()->in($this->loader->getPaths($ns)); 75 | 76 | foreach ($iterator as $file) { 77 | $resource = new TwigResource($this->loader, '@' . $ns . '/' . $file->getRelativePathname()); 78 | $this->lam->addResource($resource, 'twig'); 79 | } 80 | } 81 | } 82 | } 83 | 84 | /** 85 | * Dumps all the assets 86 | */ 87 | public function dumpAssets() 88 | { 89 | $this->dumpManagerAssets($this->am); 90 | $this->dumpManagerAssets($this->lam); 91 | } 92 | 93 | /** 94 | * Dumps the assets of given manager 95 | * 96 | * Doesn't use AssetWriter::writeManagerAssets since we also want to dump non-combined assets 97 | * (for example, when using twig extension in debug mode). 98 | * 99 | * @param AssetManager $am 100 | * @param AssetWriter $writer 101 | */ 102 | protected function dumpManagerAssets(AssetManager $am) 103 | { 104 | foreach ($am->getNames() as $name) { 105 | $asset = $am->get($name); 106 | 107 | if ($am instanceof LazyAssetManager) { 108 | $formula = $am->getFormula($name); 109 | } 110 | 111 | $this->writer->writeAsset($asset); 112 | 113 | if (!isset($formula[2])) { 114 | continue; 115 | } 116 | 117 | $debug = isset($formula[2]['debug']) ? $formula[2]['debug'] : $am->isDebug(); 118 | $combine = isset($formula[2]['combine']) ? $formula[2]['combine'] : null; 119 | 120 | if (null !== $combine ? !$combine : $debug) { 121 | foreach ($asset as $leaf) { 122 | $this->writer->writeAsset($leaf); 123 | } 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/SilexAssetic/AsseticServiceProvider.php: -------------------------------------------------------------------------------- 1 | isset($app['debug']) ? $app['debug'] : false, 35 | 'formulae_cache_dir' => null, 36 | 'auto_dump_assets' => isset($app['debug']) ? !$app['debug'] : true, 37 | ), $app['assetic.options']); 38 | 39 | // initializing lazy asset manager 40 | if (isset($app['assetic.formulae']) && 41 | !is_array($app['assetic.formulae']) && 42 | !empty($app['assetic.formulae']) 43 | ) { 44 | $app['assetic.lazy_asset_manager']; 45 | } 46 | 47 | return $app['assetic.factory']; 48 | }; 49 | 50 | /** 51 | * Factory 52 | * 53 | * @return Assetic\Factory\AssetFactory 54 | */ 55 | $app['assetic.factory'] = function () use ($app) { 56 | $root = isset($app['assetic.path_to_source']) ? $app['assetic.path_to_source'] : $app['assetic.path_to_web']; 57 | $factory = new AssetFactory($root, $app['assetic.options']['debug']); 58 | $factory->setAssetManager($app['assetic.asset_manager']); 59 | $factory->setFilterManager($app['assetic.filter_manager']); 60 | 61 | return $factory; 62 | }; 63 | 64 | /** 65 | * Asset writer, writes to the 'assetic.path_to_web' folder 66 | * 67 | * @return Assetic\AssetWriter 68 | */ 69 | $app['assetic.asset_writer'] = function () use ($app) { 70 | return new AssetWriter($app['assetic.path_to_web']); 71 | }; 72 | 73 | /** 74 | * Asset manager 75 | * 76 | * @return Assetic\AssetManager 77 | */ 78 | $app['assetic.asset_manager'] = function () use ($app) { 79 | return new AssetManager(); 80 | }; 81 | 82 | /** 83 | * Filter manager 84 | * 85 | * @return Assetic\FilterManager 86 | */ 87 | $app['assetic.filter_manager'] = function () use ($app) { 88 | return new FilterManager(); 89 | }; 90 | 91 | /** 92 | * Lazy asset manager for loading assets from $app['assetic.formulae'] 93 | * (will be later maybe removed) 94 | */ 95 | $app['assetic.lazy_asset_manager'] = function () use ($app) { 96 | $formulae = isset($app['assetic.formulae']) ? $app['assetic.formulae'] : array(); 97 | $options = $app['assetic.options']; 98 | $lazy = new LazyAssetmanager($app['assetic.factory']); 99 | 100 | if (empty($formulae)) { 101 | return $lazy; 102 | } 103 | 104 | foreach ($formulae as $name => $formula) { 105 | $lazy->setFormula($name, $formula); 106 | } 107 | 108 | if ($options['formulae_cache_dir'] !== null && $options['debug'] !== true) { 109 | foreach ($lazy->getNames() as $name) { 110 | $lazy->set($name, new AssetCache( 111 | $lazy->get($name), 112 | new FilesystemCache($options['formulae_cache_dir']) 113 | )); 114 | } 115 | } 116 | 117 | return $lazy; 118 | }; 119 | 120 | $app['assetic.dumper'] = function () use ($app) { 121 | return new Dumper( 122 | $app['assetic.asset_manager'], 123 | $app['assetic.lazy_asset_manager'], 124 | $app['assetic.asset_writer'] 125 | ); 126 | }; 127 | 128 | if (isset($app['twig'])) { 129 | $app->extend('twig', function ($twig, $app) { 130 | $twig->addExtension(new AsseticExtension($app['assetic'])); 131 | 132 | return $twig; 133 | }); 134 | 135 | $app->extend('assetic.lazy_asset_manager', function ($am, $app) { 136 | $am->setLoader('twig', new TwigFormulaLoader($app['twig'])); 137 | 138 | return $am; 139 | }); 140 | 141 | $app->extend('assetic.dumper', function ($helper, $app) { 142 | $helper->setTwig($app['twig'], $app['twig.loader.filesystem']); 143 | 144 | return $helper; 145 | }); 146 | } 147 | } 148 | 149 | /** 150 | * Bootstraps the application. 151 | * 152 | * @param \Silex\Application $app The application 153 | */ 154 | public function boot(Application $app) 155 | { 156 | 157 | // Register our filters to use 158 | if (isset($app['assetic.filters']) && is_callable($app['assetic.filters'])) { 159 | $app['assetic.filters']($app['assetic.filter_manager']); 160 | } 161 | 162 | /** 163 | * Writes down all lazy asset manager and asset managers assets 164 | */ 165 | $app->after(function () use ($app) { 166 | // Boot assetic 167 | $assetic = $app['assetic']; 168 | 169 | if (!isset($app['assetic.options']['auto_dump_assets']) || 170 | !$app['assetic.options']['auto_dump_assets']) { 171 | return; 172 | } 173 | $helper = $app['assetic.dumper']; 174 | if (isset($app['twig'])) { 175 | $helper->addTwigAssets(); 176 | } 177 | $helper->dumpAssets(); 178 | }); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /tests/SilexAssetic/Tests/AsseticServiceProviderTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped('Assetic was not installed.'); 17 | } 18 | } 19 | 20 | public function testEverythingLoaded() 21 | { 22 | $app = new Application(); 23 | 24 | $app->register(new AsseticServiceProvider()); 25 | $app['assetic.path_to_web'] = sys_get_temp_dir(); 26 | 27 | $app->get('/', function () use ($app) { 28 | return 'AsseticExtensionTest'; 29 | }); 30 | 31 | $request = Request::create('/'); 32 | $response = $app->handle($request); 33 | 34 | $this->assertInstanceOf('Assetic\Factory\AssetFactory', $app['assetic']); 35 | $this->assertInstanceOf('Assetic\AssetManager', $app['assetic.asset_manager']); 36 | $this->assertInstanceOf('Assetic\FilterManager', $app['assetic.filter_manager']); 37 | $this->assertInstanceOf('Assetic\AssetWriter', $app['assetic.asset_writer']); 38 | $this->assertInstanceOf('Assetic\Factory\LazyAssetManager', $app['assetic.lazy_asset_manager']); 39 | } 40 | 41 | public function testFilterFormRegistration() 42 | { 43 | $app = new Application(); 44 | $app->register(new AsseticServiceProvider()); 45 | $app['assetic.path_to_web'] = sys_get_temp_dir(); 46 | 47 | $app->extend('assetic.filter_manager', function($fm, $app) { 48 | $fm->set('test_filter', new \Assetic\Filter\CssMinFilter()); 49 | 50 | return $fm; 51 | }); 52 | 53 | 54 | $app->get('/', function () use ($app) { 55 | return 'AsseticExtensionTest'; 56 | }); 57 | 58 | $request = Request::create('/'); 59 | $response = $app->handle($request); 60 | 61 | $this->assertTrue($app['assetic.filter_manager']->has('test_filter')); 62 | $this->assertInstanceOf('Assetic\Filter\CssMinFilter', $app['assetic.filter_manager']->get('test_filter')); 63 | } 64 | 65 | public function testAssetFormRegistration() 66 | { 67 | $app = new Application(); 68 | $app->register(new AsseticServiceProvider()); 69 | $app['assetic.path_to_web'] = sys_get_temp_dir(); 70 | 71 | $app->extend('assetic.asset_manager', function($am, $app) { 72 | $asset = new \Assetic\Asset\FileAsset(__FILE__); 73 | $asset->setTargetPath(md5(__FILE__)); 74 | $am->set('test_asset', $asset); 75 | 76 | return $am; 77 | }); 78 | 79 | $app->get('/', function () { 80 | return 'AsseticExtensionTest'; 81 | }); 82 | 83 | $request = Request::create('/'); 84 | $response = $app->handle($request); 85 | 86 | $this->assertTrue($app['assetic.asset_manager']->has('test_asset')); 87 | $this->assertInstanceOf('Assetic\Asset\FileAsset', $app['assetic.asset_manager']->get('test_asset')); 88 | $this->assertTrue(file_exists(sys_get_temp_dir() . '/' . md5(__FILE__))); 89 | } 90 | 91 | public function testTwigAddExtension() 92 | { 93 | if (!class_exists('Twig_Environment')) { 94 | $this->markTestSkipped('Twig was not installed.'); 95 | } 96 | 97 | $app = new Application(); 98 | 99 | $app['twig'] = function () { 100 | return new \Twig_Environment(new \Twig_Loader_String()); 101 | }; 102 | 103 | $app->register(new AsseticServiceProvider()); 104 | $app['assetic.path_to_web'] = sys_get_temp_dir(); 105 | 106 | $this->assertInstanceOf('Assetic\\Extension\\Twig\\AsseticExtension', $app['twig']->getExtension('assetic')); 107 | } 108 | 109 | public function tearDown() 110 | { 111 | if (file_exists(sys_get_temp_dir() . '/' . md5(__FILE__))) { 112 | unlink(sys_get_temp_dir() . '/' . md5(__FILE__)); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 |