Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
14228f86
Commit
14228f86
authored
May 17, 2013
by
Klimov Paul
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'asset-command'
parents
9e948ccd
1c786edb
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
413 additions
and
25 deletions
+413
-25
AssetControllerTest.php
...nit/framework/console/controllers/AssetControllerTest.php
+237
-0
AssetController.php
yii/console/controllers/AssetController.php
+176
-25
No files found.
tests/unit/framework/console/controllers/AssetControllerTest.php
0 → 100644
View file @
14228f86
<?php
use
yiiunit\TestCase
;
use
yii\console\controllers\AssetController
;
/**
* Unit test for [[\yii\console\controllers\AssetController]].
* @see AssetController
*/
class
AssetControllerTest
extends
TestCase
{
/**
* @var string path for the test files.
*/
protected
$testFilePath
=
''
;
/**
* @var string test assets path.
*/
protected
$testAssetsBasePath
=
''
;
public
function
setUp
()
{
$this
->
testFilePath
=
Yii
::
getAlias
(
'@yiiunit/runtime'
)
.
DIRECTORY_SEPARATOR
.
get_class
(
$this
);
$this
->
createDir
(
$this
->
testFilePath
);
$this
->
testAssetsBasePath
=
$this
->
testFilePath
.
DIRECTORY_SEPARATOR
.
'assets'
;
$this
->
createDir
(
$this
->
testAssetsBasePath
);
}
public
function
tearDown
()
{
$this
->
removeDir
(
$this
->
testFilePath
);
}
/**
* Creates directory.
* @param $dirName directory full name.
*/
protected
function
createDir
(
$dirName
)
{
if
(
!
file_exists
(
$dirName
))
{
mkdir
(
$dirName
,
0777
,
true
);
}
}
/**
* Removes directory.
* @param $dirName directory full name
*/
protected
function
removeDir
(
$dirName
)
{
if
(
!
empty
(
$dirName
)
&&
file_exists
(
$dirName
))
{
exec
(
"rm -rf
{
$dirName
}
"
);
}
}
/**
* Creates test asset controller instance.
* @return AssetController
*/
protected
function
createAssetController
()
{
$module
=
$this
->
getMock
(
'yii\\base\\Module'
,
array
(
'fake'
),
array
(
'console'
));
$assetController
=
new
AssetController
(
'asset'
,
$module
);
$assetController
->
interactive
=
false
;
$assetController
->
jsCompressor
=
'cp {from} {to}'
;
$assetController
->
cssCompressor
=
'cp {from} {to}'
;
return
$assetController
;
}
/**
* Emulates running of the asset controller action.
* @param string $actionId id of action to be run.
* @param array $args action arguments.
* @return string command output.
*/
protected
function
runAssetControllerAction
(
$actionId
,
array
$args
=
array
())
{
$controller
=
$this
->
createAssetController
();
ob_start
();
ob_implicit_flush
(
false
);
$params
=
array
(
\yii\console\Request
::
ANONYMOUS_PARAMS
=>
$args
);
$controller
->
run
(
$actionId
,
$params
);
return
ob_get_clean
();
}
/**
* Creates test compress config.
* @param array[] $bundles asset bundles config.
* @return array config array.
*/
protected
function
createCompressConfig
(
array
$bundles
)
{
$baseUrl
=
'/test'
;
$config
=
array
(
'bundles'
=>
$this
->
createBundleConfig
(
$bundles
),
'targets'
=>
array
(
'all'
=>
array
(
'basePath'
=>
$this
->
testAssetsBasePath
,
'baseUrl'
=>
$baseUrl
,
'js'
=>
'all.js'
,
'css'
=>
'all.css'
,
),
),
'assetManager'
=>
array
(
'basePath'
=>
$this
->
testAssetsBasePath
,
'baseUrl'
=>
$baseUrl
,
),
);
return
$config
;
}
/**
* Creates test bundle configuration.
* @param array[] $bundles asset bundles config.
* @return array bundle config.
*/
protected
function
createBundleConfig
(
array
$bundles
)
{
foreach
(
$bundles
as
$name
=>
$config
)
{
if
(
!
array_key_exists
(
'basePath'
,
$config
))
{
$bundles
[
$name
][
'basePath'
]
=
$this
->
testFilePath
;
}
if
(
!
array_key_exists
(
'baseUrl'
,
$config
))
{
$bundles
[
$name
][
'baseUrl'
]
=
''
;
}
}
return
$bundles
;
}
/**
* Creates test compress config file.
* @param string $fileName output file name.
* @param array[] $bundles asset bundles config.
* @throws Exception on failure.
*/
protected
function
createCompressConfigFile
(
$fileName
,
array
$bundles
)
{
$content
=
'<?php return '
.
var_export
(
$this
->
createCompressConfig
(
$bundles
),
true
)
.
';'
;
if
(
file_put_contents
(
$fileName
,
$content
)
<=
0
)
{
throw
new
\Exception
(
"Unable to create file '
{
$fileName
}
'!"
);
}
}
/**
* Creates test asset file.
* @param string $fileRelativeName file name relative to [[testFilePath]]
* @param string $content file content
* @throws Exception on failure.
*/
protected
function
createAssetSourceFile
(
$fileRelativeName
,
$content
)
{
$fileFullName
=
$this
->
testFilePath
.
DIRECTORY_SEPARATOR
.
$fileRelativeName
;
$this
->
createDir
(
dirname
(
$fileFullName
));
if
(
file_put_contents
(
$fileFullName
,
$content
)
<=
0
)
{
throw
new
\Exception
(
"Unable to create file '
{
$fileFullName
}
'!"
);
}
}
/**
* Creates a list of asset source files.
* @param array $files assert source files in format: file/relative/name => fileContent
*/
protected
function
createAssertSourceFiles
(
array
$files
)
{
foreach
(
$files
as
$name
=>
$content
)
{
$this
->
createAssetSourceFile
(
$name
,
$content
);
}
}
// Tests :
public
function
testActionTemplate
()
{
$configFileName
=
$this
->
testFilePath
.
DIRECTORY_SEPARATOR
.
'config.php'
;
$this
->
runAssetControllerAction
(
'template'
,
array
(
$configFileName
));
$this
->
assertTrue
(
file_exists
(
$configFileName
),
'Unable to create config file template!'
);
}
public
function
testActionCompress
()
{
// Given :
$cssFiles
=
array
(
'css/test_body.css'
=>
'body {
padding-top: 20px;
padding-bottom: 60px;
}'
,
'css/test_footer.css'
=>
'.footer {
margin: 20px;
display: block;
}'
,
);
$this
->
createAssertSourceFiles
(
$cssFiles
);
$jsFiles
=
array
(
'js/test_alert.js'
=>
"function test() {
alert('Test message');
}"
,
'js/test_sum_ab.js'
=>
"function sumAB(a, b) {
return a + b;
}"
,
);
$this
->
createAssertSourceFiles
(
$jsFiles
);
$bundles
=
array
(
'app'
=>
array
(
'css'
=>
array_keys
(
$cssFiles
),
'js'
=>
array_keys
(
$jsFiles
),
),
);;
$bundleFile
=
$this
->
testFilePath
.
DIRECTORY_SEPARATOR
.
'bundle.php'
;
$configFile
=
$this
->
testFilePath
.
DIRECTORY_SEPARATOR
.
'config.php'
;
$this
->
createCompressConfigFile
(
$configFile
,
$bundles
);
// When :
$this
->
runAssetControllerAction
(
'compress'
,
array
(
$configFile
,
$bundleFile
));
// Then :
$this
->
assertTrue
(
file_exists
(
$bundleFile
),
'Unable to create output bundle file!'
);
$compressedCssFileName
=
$this
->
testAssetsBasePath
.
DIRECTORY_SEPARATOR
.
'all.css'
;
$this
->
assertTrue
(
file_exists
(
$compressedCssFileName
),
'Unable to compress CSS files!'
);
$compressedJsFileName
=
$this
->
testAssetsBasePath
.
DIRECTORY_SEPARATOR
.
'all.js'
;
$this
->
assertTrue
(
file_exists
(
$compressedJsFileName
),
'Unable to compress JS files!'
);
$compressedCssFileContent
=
file_get_contents
(
$compressedCssFileName
);
foreach
(
$cssFiles
as
$name
=>
$content
)
{
$this
->
assertContains
(
$content
,
$compressedCssFileContent
,
"Source of '
{
$name
}
' is missing in combined file!"
);
}
$compressedJsFileContent
=
file_get_contents
(
$compressedJsFileName
);
foreach
(
$jsFiles
as
$name
=>
$content
)
{
$this
->
assertContains
(
$content
,
$compressedJsFileContent
,
"Source of '
{
$name
}
' is missing in combined file!"
);
}
}
}
yii/console/controllers/AssetController.php
View file @
14228f86
...
...
@@ -12,17 +12,32 @@ use yii\console\Exception;
use
yii\console\Controller
;
/**
* This command allows you to combine and compress your JavaScript and CSS files.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
AssetController
extends
Controller
{
/**
* @var string controller default action ID.
*/
public
$defaultAction
=
'compress'
;
/**
* @var array list of asset bundles to be compressed.
* The keys are the bundle names, and the values are the configuration
* arrays for creating the [[yii\web\AssetBundle]] objects.
*/
public
$bundles
=
array
();
/**
* @var array list of paths to the extensions, which assets should be also compressed.
* Each path should contain asset manifest file named "assets.php".
*/
public
$extensions
=
array
();
/**
* @var array
* @var array list of asset bundles, which represents output compressed files.
* You can specify the name of the output compressed file using 'css' and 'js' keys:
* For example:
* ~~~
* 'all' => array(
* 'css' => 'all.css',
...
...
@@ -30,34 +45,74 @@ class AssetController extends Controller
* 'depends' => array( ... ),
* )
* ~~~
* File names can contain placeholder "{ts}", which will be filled by current timestamp, while
* file creation.
*/
public
$targets
=
array
();
/**
* @var array configuration for [[yii\web\AssetManager]] instance, which will be used
* for assets publishing.
*/
public
$assetManager
=
array
();
/**
* @var string|callback Java Script file compressor.
* If a string, it is treated as shell command template, which should contain
* placeholders {from} - source file name - and {to} - output file name.
* If an array, it is treated as PHP callback, which should perform the compression.
*
* Default value relies on usage of "Closure Compiler"
* @see https://developers.google.com/closure/compiler/
*/
public
$jsCompressor
=
'java -jar compiler.jar --js {from} --js_output_file {to}'
;
/**
* @var string|callback CSS file compressor.
* If a string, it is treated as shell command template, which should contain
* placeholders {from} - source file name - and {to} - output file name.
* If an array, it is treated as PHP callback, which should perform the compression.
*
* Default value relies on usage of "YUI Compressor"
* @see https://github.com/yui/yuicompressor/
*/
public
$cssCompressor
=
'java -jar yuicompressor.jar {from} -o {to}'
;
/**
* Combines and compresses the asset files according to the given configuration.
* During the process new asset bundle configuration file will be created.
* You should replace your original asset bundle configuration with this file in order to use compressed files.
* @param string $configFile configuration file name.
* @param string $bundleFile output asset bundles configuration file name.
*/
public
function
actionCompress
(
$configFile
,
$bundleFile
)
{
$this
->
loadConfiguration
(
$configFile
);
$bundles
=
$this
->
loadBundles
(
$this
->
bundles
,
$this
->
extensions
);
$targets
=
$this
->
loadTargets
(
$this
->
targets
,
$bundles
);
$this
->
publishBundles
(
$bundles
,
$this
->
publishOptions
);
$this
->
publishBundles
(
$bundles
,
$this
->
assetManager
);
$timestamp
=
time
();
foreach
(
$targets
as
$target
)
{
foreach
(
$targets
as
$name
=>
$target
)
{
echo
"Creating output bundle '
{
$name
}
':
\n
"
;
if
(
!
empty
(
$target
->
js
))
{
$this
->
buildTarget
(
$target
,
'js'
,
$bundles
,
$timestamp
);
}
if
(
!
empty
(
$target
->
css
))
{
$this
->
buildTarget
(
$target
,
'css'
,
$bundles
,
$timestamp
);
}
echo
"
\n
"
;
}
$targets
=
$this
->
adjustDependency
(
$targets
,
$bundles
);
$this
->
saveTargets
(
$targets
,
$bundleFile
);
}
/**
* Applies configuration from the given file to self instance.
* @param string $configFile configuration file name.
* @throws \yii\console\Exception on failure.
*/
protected
function
loadConfiguration
(
$configFile
)
{
echo
"Loading configuration from '
{
$configFile
}
'...
\n
"
;
foreach
(
require
(
$configFile
)
as
$name
=>
$value
)
{
if
(
property_exists
(
$this
,
$name
))
{
$this
->
$name
=
$value
;
...
...
@@ -74,8 +129,15 @@ class AssetController extends Controller
}
}
/**
* Creates full list of source asset bundles.
* @param array[] $bundles list of asset bundle configurations.
* @param array $extensions list of the extension paths.
* @return \yii\web\AssetBundle[] list of source asset bundles.
*/
protected
function
loadBundles
(
$bundles
,
$extensions
)
{
echo
"Collecting source bundles information...
\n
"
;
$result
=
array
();
foreach
(
$bundles
as
$name
=>
$bundle
)
{
$bundle
[
'class'
]
=
'yii\\web\\AssetBundle'
;
...
...
@@ -96,6 +158,13 @@ class AssetController extends Controller
return
$result
;
}
/**
* Creates full list of output asset bundles.
* @param array $targets output asset bundles configuration.
* @param \yii\web\AssetBundle[] $bundles list of source asset bundles.
* @return \yii\web\AssetBundle[] list of output asset bundles.
* @throws \yii\console\Exception on failure.
*/
protected
function
loadTargets
(
$targets
,
$bundles
)
{
// build the dependency order of bundles
...
...
@@ -151,26 +220,31 @@ class AssetController extends Controller
}
/**
* @param \yii\web\AssetBundle[] $bundles
* @param array $options
* Publishes given asset bundles.
* @param \yii\web\AssetBundle[] $bundles asset bundles to be published.
* @param array $options assert manager instance configuration.
*/
protected
function
publishBundles
(
$bundles
,
$options
)
{
echo
"
\n
Publishing bundles:
\n
"
;
if
(
!
isset
(
$options
[
'class'
]))
{
$options
[
'class'
]
=
'yii\\web\\AssetManager'
;
}
$am
=
Yii
::
createObject
(
$options
);
foreach
(
$bundles
as
$bundle
)
{
foreach
(
$bundles
as
$
name
=>
$
bundle
)
{
$bundle
->
publish
(
$am
);
echo
" '"
.
$name
.
"' published.
\n
"
;
}
echo
"
\n
"
;
}
/**
* @param \yii\web\AssetBundle $target
* @param string $type either "js" or "css"
* @param \yii\web\AssetBundle[] $bundles
* @param integer $timestamp
* @throws Exception
* Builds output asset bundle.
* @param \yii\web\AssetBundle $target output asset bundle
* @param string $type either "js" or "css".
* @param \yii\web\AssetBundle[] $bundles source asset bundles.
* @param integer $timestamp current timestamp.
* @throws Exception on failure.
*/
protected
function
buildTarget
(
$target
,
$type
,
$bundles
,
$timestamp
)
{
...
...
@@ -182,7 +256,7 @@ class AssetController extends Controller
foreach
(
$target
->
depends
as
$name
)
{
if
(
isset
(
$bundles
[
$name
]))
{
foreach
(
$bundles
[
$name
]
->
$type
as
$file
)
{
$inputFiles
[]
=
$bundles
[
$name
]
->
basePath
.
'/'
.
$file
;
$inputFiles
[]
=
$bundles
[
$name
]
->
basePath
.
$file
;
}
}
else
{
throw
new
Exception
(
"Unknown bundle:
$name
"
);
...
...
@@ -196,8 +270,16 @@ class AssetController extends Controller
$target
->
$type
=
array
(
$outputFile
);
}
/**
* Adjust dependencies between asset bundles in the way source bundles begin to depend on output ones.
* @param \yii\web\AssetBundle[] $targets output asset bundles.
* @param \yii\web\AssetBundle[] $bundles source asset bundles.
* @return \yii\web\AssetBundle[] output asset bundles.
*/
protected
function
adjustDependency
(
$targets
,
$bundles
)
{
echo
"Creating new bundle configuration...
\n
"
;
$map
=
array
();
foreach
(
$targets
as
$name
=>
$target
)
{
foreach
(
$target
->
depends
as
$bundle
)
{
...
...
@@ -231,6 +313,13 @@ class AssetController extends Controller
return
$targets
;
}
/**
* Registers asset bundles including their dependencies.
* @param \yii\web\AssetBundle[] $bundles asset bundles list.
* @param string $name bundle name.
* @param array $registered stores already registered names.
* @throws \yii\console\Exception if circular dependency is detected.
*/
protected
function
registerBundle
(
$bundles
,
$name
,
&
$registered
)
{
if
(
!
isset
(
$registered
[
$name
]))
{
...
...
@@ -246,6 +335,11 @@ class AssetController extends Controller
}
}
/**
* Saves new asset bundles configuration.
* @param \yii\web\AssetBundle[] $targets list of asset bundles to be saved.
* @param string $bundleFile output file name.
*/
protected
function
saveTargets
(
$targets
,
$bundleFile
)
{
$array
=
array
();
...
...
@@ -258,7 +352,7 @@ class AssetController extends Controller
}
$array
=
var_export
(
$array
,
true
);
$version
=
date
(
'Y-m-d H:i:s'
,
time
());
file_put_contents
(
$bundleFile
,
<<<EOD
$bytesWritten
=
file_put_contents
(
$bundleFile
,
<<<EOD
<?php
/**
* This file is generated by the "yii script" command.
...
...
@@ -268,60 +362,107 @@ class AssetController extends Controller
return $array;
EOD
);
if
(
$bytesWritten
<=
0
)
{
throw
new
Exception
(
"Unable to write output bundle configuration at '
{
$bundleFile
}
'."
);
}
echo
"Output bundle configuration created at '
{
$bundleFile
}
'.
\n
"
;
}
/**
* Compresses given Java Script files and combines them into the single one.
* @param array $inputFiles list of source file names.
* @param string $outputFile output file name.
* @throws \yii\console\Exception on failure
*/
protected
function
compressJsFiles
(
$inputFiles
,
$outputFile
)
{
if
(
empty
(
$inputFiles
))
{
return
;
}
echo
" Compressing JavaScript files...
\n
"
;
if
(
is_string
(
$this
->
jsCompressor
))
{
$tmpFile
=
$outputFile
.
'.tmp'
;
$this
->
combineJsFiles
(
$inputFiles
,
$tmpFile
);
$log
=
shell_exec
(
strtr
(
$this
->
jsCompressor
,
array
(
'{from}'
=>
$tmpFile
,
'{to}'
=>
$outputFile
,
'{from}'
=>
escapeshellarg
(
$tmpFile
)
,
'{to}'
=>
escapeshellarg
(
$outputFile
)
,
)));
@
unlink
(
$tmpFile
);
}
else
{
$log
=
call_user_func
(
$this
->
jsCompressor
,
$this
,
$inputFiles
,
$outputFile
);
}
if
(
!
file_exists
(
$outputFile
))
{
throw
new
Exception
(
"Unable to compress JavaScript files into '
{
$outputFile
}
'."
);
}
echo
" JavaScript files compressed into '
{
$outputFile
}
'.
\n
"
;
}
/**
* Compresses given CSS files and combines them into the single one.
* @param array $inputFiles list of source file names.
* @param string $outputFile output file name.
* @throws \yii\console\Exception on failure
*/
protected
function
compressCssFiles
(
$inputFiles
,
$outputFile
)
{
if
(
empty
(
$inputFiles
))
{
return
;
}
echo
" Compressing CSS files...
\n
"
;
if
(
is_string
(
$this
->
cssCompressor
))
{
$tmpFile
=
$outputFile
.
'.tmp'
;
$this
->
combineCssFiles
(
$inputFiles
,
$tmpFile
);
$log
=
shell_exec
(
strtr
(
$this
->
cssCompressor
,
array
(
'{from}'
=>
$inputFiles
,
'{to}'
=>
$outputFile
,
'{from}'
=>
escapeshellarg
(
$tmpFile
)
,
'{to}'
=>
escapeshellarg
(
$outputFile
)
,
)));
@
unlink
(
$tmpFile
);
}
else
{
$log
=
call_user_func
(
$this
->
cssCompressor
,
$this
,
$inputFiles
,
$outputFile
);
}
if
(
!
file_exists
(
$outputFile
))
{
throw
new
Exception
(
"Unable to compress CSS files into '
{
$outputFile
}
'."
);
}
echo
" CSS files compressed into '
{
$outputFile
}
'.
\n
"
;
}
public
function
combineJsFiles
(
$files
,
$tmpFile
)
/**
* Combines Java Script files into a single one.
* @param array $inputFiles source file names.
* @param string $outputFile output file name.
*/
public
function
combineJsFiles
(
$inputFiles
,
$outputFile
)
{
$content
=
''
;
foreach
(
$
f
iles
as
$file
)
{
foreach
(
$
inputF
iles
as
$file
)
{
$content
.=
"/*** BEGIN FILE:
$file
***/
\n
"
.
file_get_contents
(
$file
)
.
"/*** END FILE:
$file
***/
\n
"
;
}
file_put_contents
(
$
tmp
File
,
$content
);
file_put_contents
(
$
output
File
,
$content
);
}
public
function
combineCssFiles
(
$files
,
$tmpFile
)
/**
* Combines CSS files into a single one.
* @param array $inputFiles source file names.
* @param string $outputFile output file name.
*/
public
function
combineCssFiles
(
$inputFiles
,
$outputFile
)
{
// todo: adjust url() references in CSS files
$content
=
''
;
foreach
(
$
f
iles
as
$file
)
{
foreach
(
$
inputF
iles
as
$file
)
{
$content
.=
"/*** BEGIN FILE:
$file
***/
\n
"
.
file_get_contents
(
$file
)
.
"/*** END FILE:
$file
***/
\n
"
;
}
file_put_contents
(
$
tmp
File
,
$content
);
file_put_contents
(
$
output
File
,
$content
);
}
/**
* Creates template of configuration file for [[actionCompress]].
* @param string $configFile output file name.
*/
public
function
actionTemplate
(
$configFile
)
{
$template
=
<<<EOD
...
...
@@ -348,6 +489,16 @@ return array(
),
);
EOD;
file_put_contents
(
$configFile
,
$template
);
if
(
file_exists
(
$configFile
))
{
if
(
!
$this
->
confirm
(
"File '
{
$configFile
}
' already exists. Do you wish to overwrite it?"
))
{
return
;
}
}
$bytesWritten
=
file_put_contents
(
$configFile
,
$template
);
if
(
$bytesWritten
<=
0
)
{
echo
"Error: unable to write file '
{
$configFile
}
'!
\n\n
"
;
}
else
{
echo
"Configuration file template created at '
{
$configFile
}
'.
\n\n
"
;
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment