Working out how Yii2 finds theme resources when using fallbacks - php

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.

Related

Yii2 make a path alias from information stored in DB

Right now I'm trying to implement themming for my Yii2 based project.
How I see the thing now:
User chooses an application theme from the list on the settings
page in backend.
Using yii2-settings I'm saving all the
configuration data in DB (pretty easy).
In the application
bootstrap.php I'm creating new alias called #theme. Basically it
should lead us to a application theme base path (used in search
paths, assets manager, e.t.c.).
According to official
documentation, that's how I configured my view component:
'view' => [
'theme' => [
'basePath' => '#theme',
'baseUrl' => '#theme',
'pathMap' => [
'#app/views' => '#theme',
'#app/widgets' => '#theme/widgets',
'#app/modules' => '#theme/modules',
],
],
],
An issue I have is with p.3. According to yii2-settings documentation that's how I supposed to read the settings:
$theme = Yii::$app->settings->get('name', 'general');
Yii::setAlias('#theme', realpath(dirname(__FILE__)."/../../themes/$theme"));
But obviously, it's not working for me because of yii2-settings component didn't initialized yet when bootstrap.php is called. I've been trying to initialize it later in the init() method of my base controller, then adjust other aliases manually, but I feel that way being somewhat 'unclean', and also it still fails because of #theme alias is also used in asset file which is Yii2 starting to publish before calling the controller's init method.
So does anyone has any thoughts of how to do that 'hacking' the code as less as possible? I know I could just move configuration to some file, then read it manually before the application initialization, but it's still not the way I want to go.
Maybe there's some way to override some system component to set the alias after db component is loaded, but before view component configuration? Or Yii loads this components in a different order? Anyway. Any help would be appreciated!
You could try an Application Event in bootstrap:
\Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) {
$theme = Yii::$app->settings->get('name', 'general');
Yii::setAlias('#theme', realpath(dirname(__FILE__)."/../../themes/$theme"));
});
OR in configuration file:
[
'on beforeRequest' => function ($event) {
// ...
},
]
From Yii 2 docs:
EVENT_BEFORE_REQUEST This event is triggered before an application
handles a request. The actual event name is beforeRequest.
When this event is triggered, the application instance has been
configured and initialized. So it is a good place to insert your
custom code via the event mechanism to intercept the request handling
process. For example, in the event handler, you may dynamically set
the yii\base\Application::$language property based on some parameters.
Here's the final solution:
config/bootstrap.php:
// Setting a temporary path for components configuration - will be changed later
Yii::setAlias('#theme', realpath(dirname(__FILE__)."/../../themes/"));
config/main.php
'components' => [
'view' => [
'theme' => [
'basePath' => '#theme',
'baseUrl' => '#theme',
'pathMap' => [
'#app/views' => '#theme',
'#app/widgets' => '#theme/widgets',
'#app/modules' => '#theme/modules',
],
],
],
],
'on beforeRequest' => function ($event) {
$theme = Yii::$app->settings->get('theme', 'general');
Yii::setAlias('#theme', realpath(dirname(__FILE__)."/../../themes/$theme"));
},

Yii2 combining & compressing assets not working with groups of bundles

I'm having trouble understanding how combine&compress of Yii2 assets work. I read the section in the guide (http://www.yiiframework.com/doc-2.0/guide-structure-assets.html) still I cannot make it work or at least understand the very basics of this matter.
From the example given there I am not able to reproduce that and solve the following scenario.
AppAsset contains the main css/js for the application. Shared and essential code is supposed to be included here. This one depends on another file called ExternalAssets which in turn depends on YiiAsset, BootstrapAsset and so forth.
CheckoutAsset contains code only relevant to the checkout process. Should be included as well with the above because it add custom functionality but only relevant to this section. $depends on AppAsset.
ProductViewAsset is the same as above but related to the visualization of a given product.
The asset configuration is given:
'bundles' => [
'yii\web\JqueryAsset',
'rmrevin\yii\fontawesome\AssetBundle',
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
'yii\bootstrap\BootstrapPluginAsset',
'yii\widgets\ActiveFormAsset',
'frontend\assets\ExternalAssets',
'frontend\assets\AppAsset',
],
'targets' => [
'app' => [
'class' => 'yii\web\AssetBundle',
'basePath' => '#webroot/assets',
'baseUrl' => '#web/assets',
'js' => 'js/app-{hash}.js',
'css' => 'css/app-{hash}.css',
'depends' => [ ],
],
]
At this point I'm able to compress everything that is supposed to be common (although it maybe possible to strip some unnecessary files) but in the pages that use the ProductViewAsset or the CheckoutAsset the files included there do not get compressed in the same fashion.
Maybe it is possible to compress everything to a single file in the checkout process (common data + checkout data) or maybe not due to caching reasons. Don't know if this is possible yet I am unable to make it work. This is as far as I got with this. I tried doing this because it seemed natural but I started having errors like this one PHP Notice 'yii\base\ErrorException' with message 'Undefined index: frontend\assets\ExternalAssets' when trying to make different asset bundle groups:
'targets' => [
'app' => [
'class' => 'yii\web\AssetBundle',
'basePath' => '#webroot/assets',
'baseUrl' => '#web/assets',
'js' => 'js/app-{hash}.js',
'css' => 'css/app-{hash}.css',
'depends' => [
// 'frontend\assets\ExternalAssets'
],
'checkout' => [
'class' => 'yii\web\AssetBundle',
'basePath' => '#webroot/assets',
'baseUrl' => '#web/assets',
'js' => 'js/checkout-{hash}.js',
'css' => 'css/checkout-{hash}.css',
'depends' => [
'frontend\assets\AppAssets'
],
],
Maybe I'm looking at the wrong approach here but I'm not able to quite figure out what is the best way of doing this. I think that compressing everything to a single file should work better than not combine&compress the files yet I think it is possible to optimize the combine&compression approach in this case.
Thanks!
I am not sure if i understand the question you are giving, this is what i interpret as your requirements.
Make a normal action in your site controller calling a view 'site/assets/'
public function actionAssets()
{
return $this->render('assets');
}
Arrange your view like this example -
<?php
use dmstr\web\AdminLteAsset;
use backend\assets\AppAsset;
use dosamigos\fileupload\FileUploadPlusAsset;
use dosamigos\fileupload\FileUploadAsset;
use dosamigos\gallery\GalleryAsset;
use dosamigos\fileupload\FileUploadUIAsset;
use dosamigos\gallery\DosamigosAsset;
use budyaga\cropper\assets\CropperAsset;
use kartik\base\Html5InputAsset;
use kartik\base\WidgetAsset;
use kartik\form\ActiveFormAsset;
use kartik\affix\AffixAsset;
use kartik\alert\AlertAsset;
use kartik\color\ColorInputAsset;
use kartik\date\DatePickerAsset;
use kartik\datetime\DateTimePickerAsset;
use kartik\depdrop\DepDropAsset;
use kartik\depdrop\DepDropExtAsset;
use kartik\file\FileInputThemeAsset;
use kartik\growl\GrowlAsset;
use kartik\base\AnimateAsset;
use kartik\select2\Select2Asset;
use kartik\sidenav\SideNavAsset;
use kartik\spinner\SpinnerAsset;
use kartik\switchinput\SwitchInputAsset;
use kartik\time\TimePickerAsset;
use kartik\touchspin\TouchSpinAsset;
use kartik\typeahead\TypeaheadAsset;
use kartik\grid\GridViewAsset;
use kartik\dialog\DialogAsset;
$view = $this;
AdminLteAsset::register($this);
AppAsset::register($this);
FileUploadPlusAsset::register($view);
FileUploadAsset::register($view);
GalleryAsset::register($view);
FileUploadUIAsset::register($view);
DosamigosAsset::register($view);
CropperAsset::register($view);
Html5InputAsset::register($view);
WidgetAsset::register($view);
ActiveFormAsset::register($view);
AffixAsset::register($this);
AlertAsset::register($view);
ColorInputAsset::register($view);
DatePickerAsset::register($view);
DateTimePickerAsset::register($view);
DepDropAsset::register($view);
DepDropExtAsset::register($view);
FileInputThemeAsset::register($view);
GrowlAsset::register($view);
AnimateAsset::register($view);
Select2Asset::register($view);
SideNavAsset::register($this);
SpinnerAsset::register($view);
SwitchInputAsset::register($view);
TimePickerAsset::register($view);
TouchSpinAsset::register($view);
TypeaheadAsset::register($view);
GridViewAsset::register($view);
DialogAsset::register($view);
?>
<?php $this->beginPage() ?>
<?php $this->beginBody() ?>
<p>Done</p>
<?php $this->endBody() ?>
<?php $this->endPage() ?>
Then make sure to hit this link before you do a deployment to prod to recompile assets.

Yii 2 multitranslation

How to enable multitranslation in yii 2 basic framework? I have tried, but it is not working. I get no error, but translation is not showing. Code:
public function actionLang(){
$lang = \Yii::$app->request->get('lang');
if($lang && in_array($lang,['en-US','ar-SA'])){
$cookie = new Cookie();
$cookie->name = '_lang';
$cookie->value = $lang;
$cookie->expire = time() + 60 * 60 * 24 * 180;
\Yii::$app->response->cookies->add($cookie);
}
$this->redirect(['index']);
}
I'm using this function in SiteController.
Internationalization in Yii is not a one-action job. Here's the documentation on how to make your website multilingual:
https://github.com/yiisoft/yii2/blob/master/docs/guide/tutorial-i18n.md
If docs are unclear, here is a tutorial:
http://code.tutsplus.com/tutorials/programming-with-yii2-localization-with-i18n--cms-23140
If you have gone through all the steps and merely wish to set the current language, you can use:
\Yii::$app->language = 'xxx';
where xxx is a language code in accordance with ISO 639-2.
Here are the mentioned standard's entries:
http://www.loc.gov/standards/iso639-2/php/code_list.php
First of all, from what I have gathered, you are trying to identify a language requested from the current request by doing $lang = \Yii::$app->request->get('lang'); and then set it in the cookie. In my opinion, this should be used as a "helper", meaning, it is useful to know the language preference of the returning client, but you still have to manage languages via URL, i.e. http://yoursite.com/en or http://yoursite.com/de should serve different languages.
Now, there are actually very good plugins out there for multilingual URL management, such as yii2-localeurls , which you can find here. I use it in production in multiple projects and highly recommend it.
To actually manage translations, you have to have a folder in the root of your project (if you are using advance template, you should have it inside frontend/backend/console ) to store the actual block translations, call it messages .
Now, under #app/messages create folders for each non-default language, for example #app/messages/de for German translations.
If you go your config in #app/config/main.php, look for i18n key inside the components array. If you can't find such a key, simply put the following into the components array:
'i18n' => [
'translations' => [
'app*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#app/messages',
'sourceLanguage' => 'en',
'fileMap' => [
'app' => 'app.php',
'app/error' => 'error.php',
],
],
'*' => [
'class' => 'yii\i18n\PhpMessageSource',
]
],
],
Now, you will need to create a translation file inside the relevant directory. In the above configuration, we declared that the default language used is en, that means that all original messages would be in English. Go to #app/messages/de and create a translations file inside that directory. You can call it whatever you like, but for this example, call it site.php.
In this site.php put the following:
return [
'Translate this!' => 'Your relevant translation here in whichever language',
'Translate this also!!!' => 'Stuff...'
];
If all done correctly, when you access your page via http://yousite.com/de, when using Yii::t('site', 'Translate this!') you should be getting 'Your relevant translation here in whichever language' instead.
The beauty of Yii 2 is that it is extremely well documented. Visit the official documentation if you are stuck, it really explains everything quite well.

how to setup multiple language in yii2 in simple way

I am working on yii2 framework.This is new framework for me. I want to setup multiple language. I tried some way but didn't got success. Can anyone please suggest me simplest way ? What should i have to do ?
I am using this reference link
http://techisworld.com/working-with-multiple-languages-app-in-yii2-framework-using-i18n-system.html
1- For dynamic content (coming from database) I usually use this:
webvimark/multilanguage
It is very easy and isolated from your app DB tables structure and code, that gives flexibility in adding/removing languages at the long term.
2- For static content (words inside the markup) in frontend as an example:
add the lines in your frontend/config/main.php file,
'i18n' => [
'translations' => [
'app*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#app/messages',
'sourceLanguage' => 'en_US',
'fileMap' => [
'app' => 'app.php'
],
],
],
],
Put you translation file app.php file inside /frontend/messages, as any Yii translation file it returns an array of translations in a key-value pairs.
Then you can translate your static content using:
Yii::t('app', 'text to be translated')

How to load a language file from a package in fuelphp?

Using the config.php always_load configuration, how does one load a language file from a package?
All of the fuelphp documentation alludes to being able to do this, but only shows the syntax for loading from a module.
Here's what I'm trying to do:
fuel/app/config/config.php
'always_load' => [
'language' => [
// loads fuel/app/lang/en/login.php into login group
'login',
],
],
fuel/app/config/production/config.php
'always_load' => [
'language' => [
// override /config/config.php with contents from
// /fuel/packages/pkg/lang/en/login.php
'lang_file_from_package' => 'login',
],
],
Packages are core extensions, which means it will merge the contents of the files found in app and in the package.
As such, there is no method to define you want to load it from the package only, other then by specifying a fully qualified pathname, which will always load just that file.

Categories