-1

Right now I'm trying to implement themming for my Yii2 based project. How I see the thing now:

  1. User chooses an application theme from the list on the settings page in backend.
  2. Using yii2-settings I'm saving all the configuration data in DB (pretty easy).
  3. 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.).
  4. 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!

lehadnk
  • 143
  • 1
  • 1
  • 6

2 Answers2

1

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.

sdlins
  • 2,195
  • 1
  • 23
  • 31
  • Thank you! This one worked well for me. First approach is not working because of app being not initialized yet while running the bootstrap script, but configuring the event inside a config file works well for me. Ended with this tricky thing is that I have to declare 'fake' @ theme path inside a bootstrap still, or Yii just can't configure the base paths. But changing the @ theme alias is also changes the other aliases automatically, so hope I won't have any other issues from using this hack :P – lehadnk May 10 '16 at 06:13
-1

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"));
},
lehadnk
  • 143
  • 1
  • 1
  • 6
  • This is what I have answered, isn't? Your configs are exactly the same, and you have used the `'on beforeRequest'` event as I said. If so, could mark my answer as your choice? This is how stackoverflow works ;-) – sdlins May 10 '16 at 16:34