If you're not familiar with using packages, I will run through it very briefly. The Class reference for the CClientScript can be found here: http://www.yiiframework.com/doc/api/1.1/CClientScript
Scenario 1, static files in public web root:
Yii::app()->clientScript->registerCSSFile( '/myassets/css/form_page_only.css' ); Yii::app()->clientScript->registerScriptFile( '/myassets/js/form_page_only.js' );
But what if the assets are in a widget or extension and need to be published, rather than simply referenced?
Scenario 2, using the http://www.yiiframework.com/doc/api/1.1/CAssetManager to publish files from :
$assetUrl = Yii::app()->assetManager->publish('/path/to/my/library/'); Yii::app()->clientScript->registerCSSFile( $assetUrl.'/css/form_page_only.css' ); Yii::app()->clientScript->registerScriptFile( $assetUrl.'/js/form_page_only.js' );
Ugh, now we've mixed in another class to learn and another line to include on each of the form views. There has to be a better way, right? Right!
Welcome to packages!
Packages let us group assets and asset paths together, ensuring that all the associated and required files get included with a single keyword. The syntax is quite simple, as most things in Yii, it's a simple keyed array.
The packages for scenario one and two would like something like this, in the main config file:
'components'=>array( ... 'clientScript'=>array( 'packages' => array( 'scenario1'=>array( // pass a baseUrl because we don't need to publish 'baseUrl'=> '/myassets/', 'css' => array( 'css/form_page_only.css' ), 'js' => array( 'js/form_page_only.js' ), ), 'scenario2'=>array( // note the use of the Yii path alias format 'basePath'=> 'path.to.my.library', 'css' => array( 'css/form_page_only.css' ), 'js' => array( 'js/form_page_only.js' ), ), ), ), );
Now, we can consistently and efficiently include the files with a single line.
In Scenario 1 form:
Or in Scenario 2 form:
Note that we're not longer having to call the assestManager directly to get the files published first, the package knows what it needs to do.
The package will publish the asset path if necessary and then register the listed css and js files.
If you have images assets that you need published as well, they will be published as long as they are in the basePath.
As you can see, this clearly makes our code more DRY and ensures that should a change in the file name or path need to be made, it can be made in a single centralized location.
It is also possible to use package definitions that you have not declared in the main config file.
As of Yii 1.1.10 you can now use the addPackage() method of the CClientScript to dynamically add a package.
So, lets take this possible scenario that would have been called without packages, using chaining rather than calling Yii::app()->clientScript directly each time, and assuming I have the following file structure:
/my/path/to/obscurefiles/ /my/path/to/obscurefiles/css/...(various css files here) /my/path/to/obscurefiles/js/...(various js files here) /my/path/to/obscurefiles/images/...(various images here)
That's a lot of repetition, and not very friendly to read. With Yii 1.1.10 we can refactor that code into something that's a little more clear:
NOTE: If I'm not using the $assetUrl within the page for anything, I can skip appending the getPackageBaseUrl() call to the end of the chain and forgo the assignment to $assetUrl entirely, like so:
Yii::app()->clientScript->addPackage('myPack', $myPackage)->registerPackage('myPack');And if you later do need to access the assetUrl for that package, you can still get the url path by simply calling Yii::app()->clientScript->getPackageBaseUrl('myPack');
Pre-Yii 1.1.10 you could accomplish this by manually tweaking the packages array of the clientScript before calling register package, but it's a lot more 'hands on' to do so, and cannot be chained:
Yii::app()->clientScript->packages['myPack'] = $myPackage; Yii::app()->clientScript->registerPackage('myPack');
It should be noted that the "depends" array can contain your custom package names, it is NOT restricted to core Yii packages. It will check your package list first, then fall back to the Yii core, the same way registerPackage does.
Therefor, it would be quite possible to have a package such as:
'packages'=>array( 'myPackage'=>array(...), 'myPackage2'=>array( ... 'depends'=>array('myPackage'), ), 'myPackage3'=>array( ... 'depends'=>array('myPackage2, jquery-ui'), ) )
I hope that helps to shed some light on the use of packages and maintainability. In my opinion, it's another one of Yii's hidden treasures -- you could go years without using it, but why put yourself through that? ;)