component initialization

Why is component initialization a feature of application components exclusively, and not a general component feature?

I find myself needing this quite often - for example, my e-commerce solution uses a number of "computations" and "features" in the form of components and behaviors that you can configure and extend as needed.

I create those components and behaviors using Yii::createComponent(), but I find myself needing to initialize most components after that, and this makes me wonder - any component created by using a piece of configuration could potentially need initialization.

I some cases, I can work around this by using a set-accessor to do the initialization, but in most cases, I find myself implementing the IApplicationComponent interface methods over and over for many components, and since they’re not application components, I also find myself having to write code to ensure that the init() method gets called.

Why isn’t initialization part of CComponent and automatically performed by YiiBase::createComponent() ?

I think the main reason is because only CApplicationComponents can be configured in main.php. So in init() you can already access it’s configured properties and do additional initialization.

For any other components you can do initialization by overriding the constructer and call parent::__constructor().

EDIT:

If i think more, i wonder, from where and when should init() be called on these non-application components?

But not only application components can be configured from the main configuration file.

I do a lot of "feature modeling" - that is, application components that are designed to be extended with additional features, in the form of components and behaviors, and I configure all of these from the main configuration file.

As an example, here’s the configuration for my shop component in an application I’m currently working on:




    'shop'=>array(

      'class'=>'Shop',

      'features'=>array(

        'subscription'=>'ShopSubscriptionFeature',

        'downloads'=>'GShopAttachmentFeature',

        'shipping'=>array(

          'class'=>'GShopShippingFeature',

          'flatRate'=>true,

        ),

      ),

      'summary' => 'ShopSummary',

      'computed'=> array(

        'products' => 'GShopComputedSummary',

        'promotions' => 'ShopComputedPromotion',

        'discount' => 'ShopComputedDiscount',

        'subtotal' => 'GShopComputedSubtotal',

        'tax' => 'ShopComputedTax',

        'shipping' => 'ShopComputedShipping',

        'total' => 'GShopComputedTotal',

      ),

    ),



In my shop component, product features and computed fields are behaviors and components attached to the main shop application component. The shopping cart and order summary generator are also components, which means I can extend or replace them when I use the shop component in different applications.

The behaviors and components are created using calls to Yii::createComponent(), which is very practical, because it’ll handle a string (a simple class name) or an array (more detailed configuration) and I don’t have to manually check or handle these different levels of configuration everywhere.

But when I create (for example) features, I have to manually initialize them after I create them - and the pattern I follow, in almost any case, is identical to that of CApplicationComponent.

Note that __construct() will not work, because __construct() happens before Yii::createComponent() has a chance to initialize the component’s attributes.

Perhaps what I really need is actually closer to CModule than CApplicationComponent. Due to the size and complexity of CModule, I guess I figured maybe it was too much for what I needed. But perhaps my application component should actually have been a module, and my components should have been application-components.

I need to ponder this more deeply… :slight_smile: