Yii2 assets clear cache - php

Everytime I update my css or js files in infoweb\menu\module\assets, I have to empty the backend\web\assets folder
is there a way to automatically clear the assets cache?

Add this in your view:
use vendor\myVendorName\myPackageName\assets\AppAsset;
AppAsset::register($this);
Add this in your config:
'components' => [
'assetManager' => [
'linkAssets' => true,
],
]
Empty assets folder, and refresh, done

there is additional property as
if (YII_ENV_DEV) {
...;
...;
...;
$config['components']['assetManager']['forceCopy'] = true;
...;
...;
}
to publish files even there are published before

If you enviroment is production I recommend to use Cache Busting :
return [
// ...
'components' => [
'assetManager' => [
'appendTimestamp' => true,
],
],
];
for more information about assets, read the Assets Yii2 documentation.

If you are developing your own plugin, you can force publish assets per bundle
(note: $sourcePath should be set)
<?php
namespace app\components\forms\redactorAssets;
use yii\web\AssetBundle;
class RedactorCutAsset extends AssetBundle {
public $sourcePath = '#app/components/forms/redactorAssets/assets';
public $js = [
'cut.js',
];
public $publishOptions = [
'forceCopy'=>true,
];
}

sudo rm -rf frontend/web/assets/*
sudo chmod 777 frontend/web/assets
./yii cache/flush-all
If this does not work:
sudo rm -rf vendor/*
composer install

I use CClientScript::registerScriptFile method in my view files:
Yii::app()->clientScript->registerScriptFile(
$this->getAssetsBase() . '/js/script.js'
);
If I modified script.js, after next page reload I will see all changes
For css files - CClientScript::registerCssFile
Yii::app()->clientScript->registerCssFile(
$this->getAssetsBase() . '/css/style.css'
);
UPDATE: if you use yii 2.0 beta, you can read some information about changes in mechanic of client helpers here: link

The AssetManager will create a hash based on the file modification time. The modification time of a directory does not change when any file is changed.
If you have an AssetBundle that has a directory as $sourcePath, the modification time of the directory is used, the hash will not change, and nothing gets copied to the web/assets directory.
I suggest overriding AssetManager::hash() in a subclass or write a function for AssetManager::$hashCallback:
'components' => [
'assetManager' => [
'hashCallback' => function($path) {
// if: $path is directory: figure out when files were changed in directory
// else: use original hash function in \yii\web\AssetManager
}
],
]
For a sample implementation for finding the max modified date over all asset files in a bundle you could look at this comment by wookie # http://php.net/manual/en/function.filemtime.php#35779
Note that modification to any asset file will create a new directory in web/assets, and regular cleanup will remain necessary. However, browser cache aside, refreshing the page will follow the latest changes.

I configure the assetManager::forceCopy=true in main-local.php for the dev environment like this
return [
'components' => [
...
'assetManager' => [
'forceCopy' => true,
]
...
],
];

Related

Cannot set "AppAsset baseurl" after settting "request baseUrl" in Yii2 advanced(php framework)

I'm using Yii2 advanced, which have frontend and backend, I'm using two domain to access frontend and backend respectively.
For some reason, I add a baseUrl(/admin) to backend, which will cause links like http://backend.example.com/controller/action change to backend.example.com/admin/controller/action, after this changing, the page can be load correctly
'components' => [
'request' => [
'csrfParam' => '_csrf-backend',
//All requests will add "/admin",e.g:
//backend.example.com/controller/action will change to
//backend.example.com/admin/controller/action
'baseUrl' => '/admin',
],
],
But it caused another problem: assets can't load cause it add /admin too
I tried changing the baseUrl of AppAssets in backend/assets/AppAsset.php, but not working
<?php
namespace backend\assets;
use yii\web\AssetBundle;
/**
* Main backend application asset bundle.
*/
class AppAsset extends AssetBundle
{
public $basePath = '#webroot';
public $baseUrl = '#web';
public $css = [
'css/site.css',
];
public $js = [
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
}
It acts like $baseUrl doesn't exists, no matter what value I set to $baseUrl, the page just keep requesting /admin/assets/86321cf/xxxx.js, how can I remove the /admin by modifying settings in backend/assets/AppAsset.php?
If I use the registerJsFile() method to register js to the page
$this->registerJsFile('plugins/ImageViewer/imageviewer.min.js', ['position' => View::POS_END, 'depends'=>JqueryAsset::class]);
it's loading the correct path(which means not adding /admin to the path)
So I was wondering how can I let the page load correct path of assets by changing configurations of backend/assets/AppAsset.php or can I solve it by changing configurations in other file?
$baseUrl in asset - specifies the URL corresponding to the directory basePath. Like basePath, if you specify the sourcePath property, the asset manager will publish the assets and overwrite this property accordingly.
try to write #app/backend/web in baseUrl
since it seems to me that #web after being assigned to the request will be equal to / admin
OK, after massive searching and asking people, I solve this myself, it turns out that we can set the $baseUrl of backend/assets/AppAsset.php in main.php in this way
'components' => [
'assetManager' => [
//after settting components.request.baseUrl='/admin', the assets url will automatically add "/admin" to its url
//to avoid this, we can set the asset baseUrl in components.assetManager.baseUrl, set it to '/assets'
'baseUrl' => '/assets',
],
'request' => [
'csrfParam' => '_csrf-backend',
//All requests will add "/admin",e.g:
//www.example.com/controller/action will change to
//www.example.com/admin/controller/action
'baseUrl' => '/admin',
],
// other configs....
],
These two link inspired me:
Yii - Assets
Override Yii2 assetManager config in controller

Laravel package config does not merge

I am developing several packages and would like to have a single config file for all of them if they are to be published.
Inside my service provider I did this:
public function boot()
{
$this->publishes([
__DIR__ . '/config/custom.php' => config_path('custom.php'),
]);
}
public function register()
{
$this->mergeConfigFrom(
__DIR__ . '/config/custom.php', 'custom'
);
}
Config:
return [
'containers' => [
...
]
];
And surely enough, if I publish it, it creates the file with values inside. But if a file already exists, having different keys:
return [
'xxxyyy' => [
...
],
];
publishing doesn't do anything. I would expect it to look like:
return [
'xxxyyy' => [
...
],
'containers' => [
...
]
];
What am I doing wrong?
In case anyone else is baffled by this, I have tested several cases and here is my explanation (official docs).
$this->publishes part enables the package config to be published by vendor:publish command. Nothing to explain here.
$this->mergeConfigFrom part enables the package config to be merged with currently published copy. Merge in this case means merged from Laravel config() scope.
This means that going to artisan tinker and running config('key') (where key is name of your config file) will return nothing if there is no published file and you don't have mergeConfigFrom. If a file is published and has other key value pairs which are not present in your package config and you have mergeConfigFrom present, config('key') will return merged array of values from a published file together with values from your config.
If a file with a same config name exists in your root config folder, and your package internally uses the same config name but you don't have mergeConfigFrom, config('key') will return only contents of a file inside root config folder, and will ignore everything from your package as you didn't provide a way for Laravel to see this as a "global" configuration. Your package will keep internally using the package config, but from app scope you will not be able to fetch it.

Yii2 load modules

how I can load an external-site module? I have a common module I need to load in distinct Yii2 sites, like advanced-template my idea is to have a common dir where store generic modules wich I can load to each site. A file system structure can be like this:
/
site-1/
(loads modules from common-modules dir for site-1)
site-2/
(loads modules from common-modules dir for site-2)
common_sites_modules/
module-1/
module-2/
carrello/
Carrello.php
Each site in his configuration have to load modules from common-modules/
Is possible to implement this structure?
Edit 1
The configuration:
'cart' => [
'class' => dirname(dirname(dirname(__DIR__))) . '/common_sites_modules/carrello/Carrello',
'params' =>[
...
],
'components' => [
...
],
],
and this is the first line of the class Carrello.php:
<?php
namespace common_sites_modules\carrello;
...
The top bar of editor with the path of the class and the error returned by Yii:
Edit 2:
Thanks to #Yupik for support and suggests, the new settings:
bootstrap.php:
Yii::setAlias('#common-modules', dirname(dirname(dirname(__DIR__))) . '/common_sites_modules');
main-local.php:
'class' => '#common-modules\carrello\Carrello',
The generated error:
Like suggested in the comments the solution is to declare an alias and then use the name of alias for call the module. Like suggested by #Yupik I've set in the common/config/bootstrap.php an alias as follow:
Yii::setAlias('#common_modules', dirname(dirname(dirname(__DIR__))) . '/common_modules');
In the main configuration:
'carrello' => [
'class' => ''common_modules\carrello\Carrello',
...
]
Obviously namespace have to be configured based on the position on filesystem.
Thanks for the suggestions
Yes, we can do this by making a symlink of common_sites_modules directory in both site folder (site1, site2).

Where should I put a library in a Yii project that is not available via Composer?

I can't put the library under vendor/ because that directory is ignored in .gitignore. I put it under bing-ads/ and I have
<?php
namespace app\models;
include 'bing-ads\v10\bingads\ClientProxy.php';
use \Yii;
use BingAds\Proxy\ClientProxy;
to access it. It works for console commands/actions, but I have a feeling it will not work during a web call because the root directory will be web/. Where should I put this library and how can I access it via both console actions and web actions?
The Microsoft PHP library is located here.
I found a way by adding the file paths to the autoload section of composer.json. I remembered that I had to do that for some of the other libraries as well, even the ones available via Composer.
"autoload": {
"classmap": [
"vendor/googleads/googleads-php-lib/src/Google/Api/Ads/Common/Util",
"vendor/googleads/googleads-php-lib/src/Google/Api/Ads/AdWords/Util/v201605",
"bing-ads/v9/bingads/CustomerManagementClasses.php",
"bing-ads/v10/bingads/v10/CampaignManagementClasses.php",
"bing-ads/v10/bingads/v10/BulkClasses.php",
"bing-ads/v10/bingads/ClientProxy.php"
]
}
Then I ran
$ composer install
...
Generating autoload files
I'm not sure this is the best way though.
You could store them wherever you want e.g. in a folder named "BingAds".
Just add the alias as example in a common base config file /common/config/base.php which is included in your console as well as in your web application e.g. for your /web/index.php
$config = \yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../common/config/base.php'),
require(__DIR__ . '/../common/config/web.php'),
require(__DIR__ . '/../config/base.php'),
require(__DIR__ . '/../config/web.php')
);
Inside this common/config/base.php you could add your settings, extensions etc. which are valid for both the console and your web application
<?php
$config = [
...
'aliases' => [
'#BingAds' => '#app/BingAds/v10',
'#BingAds/Proxy' => '#app/BingAds/v10/bingads',
],
];
Your Clientproxy.php is stored as example in the directory /BingAds/Proxy/.
Then you don't have to include your files every time you want to use them and just write.
use BingAds\Proxy\ClientProxy;
I have unpacked your linked zip file and stored the files of the directory Bing Ads API in PHP\PHP\Bing Ads API in PHP to my application root directory BingAds whith the aliases mentioned above.
I have tested it by creating a clientProxy object in both a console and web application.
$test = new ClientProxy('test');
var_dump($test);
Both Printed out
object(BingAds\Proxy\ClientProxy)[140]
private 'authenticationToken' => null
private 'username' => null
private 'password' => null
private 'developerToken' => null
private 'wsdlUrl' => string 'test' (length=4)
private 'accountId' => null
private 'customerId' => null
private 'service' => null
private 'namespace' => null
I haven`t tested out other classes but I guess you get how it works.
Add this to your composer.json:
{
"repositories": [
{
"type": "package",
"package": {
"name": "microsoft/bing-ads",
"version": "9.0.0",
"dist": {
"url": "https://code.msdn.microsoft.com/Bing-Ads-API-Version-9-in-fb27761f/file/159208/2/Bing%20Ads%20API%20in%20PHP.zip",
"type": "zip"
},
"autoload": {
"classmap": [
"PHP/Bing Ads API in PHP/v10/bingads/"
]
}
}
}
],
"require": {
"microsoft/bing-ads": "9.0.0"
}
}
Then add composer generated autload.php file if you haven't already.
Then you can call the BingAds\Proxy\ClientProxy() without includes.
There's no better way:)
It's best to place external library to extensions directory.
And in config do
return [
'import' => [
'application.extensions.bing-ads.v10.bingads.ClientProxy',
],
...
];
in main and in console configs.
I usually just put the code in a components folder. If you're using the basic template, this folder can be under your application root; if you're using the advanced template, this folder can be under the necessary app: frontend, backend, console, or common. I recommend putting it under common for reasons I shall explain later
Under every app config, Yii 2 uses the ::setAlias method to assign different aliases to the key folders. In the basic app template, #app refers to the application root. While in the advanced template #app may refer to any of backend, frontend, or console.
If your library code is under backend, you can access it like so
namespace backend\controllers;
use yii\web\Controller;
use backend\components\MyLibCode;
class SiteController extends Controller
{
public function actionIndex()
{
$mlb = new MyLibCode();
// ...
}
}
However, it is good Yii 2 practice to have common library code in the common folder. So if this library code is to be used across apps, I suggest you put it into the common\components folder and replace backend with common in the use statement in the code above.
p.s: Justinas method also works; it's borrowed from Yii 1. But this may become cumbersome because this asks Yii to load the class when the application starts. If there is some heavy-lifting in that file, it may be detrimental to the app's performance.

Working out how Yii2 finds theme resources when using fallbacks

I am using Yii2 and have been reading about theming and theme inheritance; however have some questions:
Consider the following example:
'view' => [
'theme' => [
'pathMap' => [
'#app/views' => [
'#app/themes/current',
'#app/themes/default',
],
],
'baseUrl' => '#web/themes/current',
'basePath' => '#webroot/themes/current',
],
],
Now, imagine we request the theme file foo; as I understand it this will first be looked for in the following order:
#app/themes/current/foo.php
#app/themes/default/foo.php
#app/views/foo.php
Now imagine foo.php isn't found in the #app/themes/current/ theme, so it would use the file found in #app/themes/default/.
Now, considering the baseUrl and basePath settings I am a little confused how these are used in these situations.
Now, imagine foo.php references an image file inside the file, wouldn't this still attempt to find #web/themes/current/images/myImage.jpg rather than #web/themes/default/images/myImage.jpg?
In this case, basePath is worthless. Because basePath is only applied when
pathMap is empty.
basePath is not a fallback, It is a shortcut of pathMap, quick use when you only have one theme.
'pathMap' => [
'#app/views' => [
'#app/themes/current/views',
],
],
Equivalent to:
'basePath' => '#app/themes/current',
(Yii understands that folder #app/themes/current/views exist)
baseUrl: It is returned when you call $this->theme->getBaseUrl() in view file. Less worth with multi theme.
About fallback for static files. Theming fallback is not designed for this purpose.
Point your links inside file like this exmaple from docs:
$theme = $this->theme;
// returns: $theme->baseUrl . '/img/logo.gif'
$url = $theme->getUrl('img/logo.gif');
// returns: $theme->basePath . '/img/logo.gif'
$file = $theme->getPath('img/logo.gif');
It will get file from current theme directory.

Categories