Yii2 Configuration Design.

May be it will be stupid question, but still…Could anybody explain me some basic syntax for including components in configuration file? I can’t understand why components including doesn’t have unified syntax like in hypothetical example below.

The Yii2 configuration code block:




'components' => [

        'urlManager' => [

            'class' => 'yii\web\UrlManager',

            'showScriptName' => false,

            'enablePrettyUrl' => true,

        ],

        'cache' => [

            'class' => 'yii\caching\FileCache',

        ],

        'user' => [

            'identityClass' => 'app\models\User',

        ],

        'errorHandler' => [

            'errorAction' => 'site/error',

        ],

        'mail' => [

            'class' => 'yii\swiftmailer\Mailer',

        ],

        'log' => [

            'traceLevel' => YII_DEBUG ? 3 : 0,

            'targets' => [

                [

                    'class' => 'yii\log\FileTarget',

                    'levels' => ['error', 'warning'],

                ],

            ],

        ],

    ],



The expected form:




'components' => [

        'UrlManager' => [

            'class' => 'yii\web\UrlManager',

            'showScriptName' => false,

            'enablePrettyUrl' => true,

        ],

        'FileCache' => [

            'class' => 'yii\caching\FileCache',

        ],

        'User' => [

            'class' => 'yii\path\to\User', #?

            'identityClass' => 'app\models\User',

        ],

        'ErrorHandler' => [

            'class' => 'yii\path\to\ErrorHandler',

            'errorAction' => 'site/error',

        ],

        'Mailer' => [

            'class' => 'yii\swiftmailer\Mailer',

        ],

        'log' => [

            'class' => 'yii\log\FileTarget',  #?

            'traceLevel' => YII_DEBUG ? 3 : 0,

            'targets' => [

                [

                    'levels' => ['error', 'warning'],

                ],

            ],

        ],

    ],



As you can see, the main changes are:

  1. Component name and class name match - I think is logical and easy to remember.

  2. Each component has class key value pair at the top level of component’s array.

  3. Subsequent key value pairs are components options.

I find it hard to learn when there is weak logical link and many aliases for component’s names.


Sorry for the mistakes I’ve made. I’m not English man.

Component ‘names’ are used as $app properties, like this: \Yii::$app->email, and property names are camelCased.

Also notice that ‘cache’, for example, can use different mechanism: FileCache, ApcCache and so on.

You can think of it as dependency injection.

What about class declaration in each component?

Well, you can set them in any component config item, but this is a little bit redundant.

Component classes are usually set when you need either to use concrete class (Apc instead of File and so on) or you have extended core component and want to use your own version instead.

Base component classes are set inside registerCoreComponents() function of Appcication class (yii\base\Application, yii\web\Application, …)

Thank you for replay, I think I caught what you’re talking. Far as I understand, ‘class’ key means the class with it is implemented only for some components, isn’t it?

You specify class key if you want to overwrite the default class used by that component or if you’re adding a custom component.

Hmm, not sure if I was clear.

Let me put it this way:

Assume you want to use a user component.

Every component has its own class. Default class for user is yii\web\User, it is set in yii\web\Application::registerCoreComponents.

Core and application code use it this way:


$user = \Yii::$app->user

or this way (these two are equal because of magic method calls)


$user = \Yii::$app->getUser()

which, in fact, is a shortcut for


\Yii::$app->getComponent('user')

and getComponent is a method of yii\base\Module that creates (or returns already created) component object (instance of configured class)

Now let’s suppose you want to override user component by your own implementation. All you need to do is set your own component class in config: ‘class’ => ‘app\components\TwistedUser’. Now all the calls to \Yii::$app->user will create your own class instead.

No need to hack the core, no need to redefine core methods, just inject your own dependency and that’s it. Very convenient.

Note that in most cases you don’t need to override the whole class. You can just set come keys inside config array and they will be passed to component constructor, overriding public properties of component class.

Here’s an example:

Suppose I want to use authclient extension for facebook login. The only thing I want to change is authUrl, because FB complains about opening auth in ‘page’ mode.

So I add one line to config:


'facebook' => [

    'class' => 'yii\authclient\clients\Facebook', // I could switch to my own class here, but I'm too lazy

    'authUrl' => 'https://www.facebook.com/dialog/oauth?display=popup', // <<< ADDED BY OREY

    'clientId' => '...',

    'clientSecret' => '...',

],

and voila, new auth URL.

Speaking about your own components, I think you must set ‘class’ key every time, because there are no ‘default’ values.

One last notice about naming: you can have two components with the same class (but different config options). For example:




'user' => [

    'class' => 'yii\web\User',

    'identityClass' => 'app\models\User',

    'loginUrl' => '/profile/user/login',

],

'admin' => [

    'class' => 'yii\web\User',

    'identityClass' => 'app\models\Admin',

    'loginUrl' => '/admin/backend/login',

],



As you can see, you cannot give these config keys the same name (like ‘User’ in your example of the expected form), because we want to have two instances at the same time.