Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application initializers #2775

Closed
alpharder opened this issue Mar 17, 2014 · 7 comments
Closed

Application initializers #2775

alpharder opened this issue Mar 17, 2014 · 7 comments

Comments

@alpharder
Copy link

@alpharder alpharder commented Mar 17, 2014

For now it's only possible to run code when application is initializing with extension bootstrap classes.

The problem: I need to run code on application init part without using extended Application class.

The possible solution: use Application extensions property, like this:

// configuration file
return [
    'extensions' => array_merge(
        require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
        [
             ['bootstrap'=>'path\to\Class']
        ]
    )
];

This solution isn't clear and may cause different side-effects when managing extensions.

The perfect solution: application initializer classes. They should be specified at application configuration, like this:

return [
    'initializers' => [
        'path\to\Class',
        ...
    ]
]; 

In Laravel, they're called Service providers.

yii\base\Application::initExtensions() will be able to add extensions' bootstrap classes to initializers property and allow new method yii\base\Application::runInitializers() to call their init() method.

@Ragazzo
Copy link
Contributor

@Ragazzo Ragazzo commented Mar 17, 2014

in L4 service providers are for DI, no ? Anyway i see this like initializers in rails right ? Could be useful.

@alpharder
Copy link
Author

@alpharder alpharder commented Mar 17, 2014

@Ragazzo L4? of course not only for DI, there are use-cases different from IoC registrations.

The concept of initializers can be useful for any purposes.
For example, in a CMS for my projects there are a lot of base modules (user, mail, etc.).
Any project-specific functionality is merged into a separate module.

Each module has it's own configuration file, which is automatically required and merged with application config before application runs. For example, socialnetworks module needs to add additional login method class to user module, so it's configuration file looks like:

<?php
return [
  'modules'=>[
    'user'=>[
      'loginMethods'=>['social'=>'path\to\LoginMethodClass']
    ],
    'socialNetworks'=>'path\To\ModuleClass'
  ]
];

So resulting config will be merged with this, and as a result "user" module will have additional "social" login method. This solution is a dirty walkaround (I have to generate config files, regenerate when they change, etc.), the cleaner solution is:

  • socialnetworks module's initializer class is added to app config
  • It registers additional login method for user module:
<?php
class SocialNetworksInitializer implements IAmInitializer
{
      public static function init(Application $app)
      {
          $app->getModule('user')->loginMethods['social'] = 'path\to\LoginMethodClass';
      }
}
@alpharder
Copy link
Author

@alpharder alpharder commented Mar 17, 2014

I've just read about Rails initializer files. Yes, I propose similar concept.

@Ragazzo
Copy link
Contributor

@Ragazzo Ragazzo commented Mar 17, 2014

Maybe we also should add two events for application BEFORE_INIT / AFTER_INIT ?

@alpharder
Copy link
Author

@alpharder alpharder commented Mar 17, 2014

I'm not sure about BEFORE_INIT - when to trigger it?

// Application constructor
public function __construct($config = [])
{
  Yii::$app = $this;
  // 1. Nothing have happened here.
  // On this line it's still possible to place some code 
  // that configures PHP like `ini_set()`

  $this->preInit($config); // initializes app paths and timezone
  $this->registerErrorHandlers();
  $this->registerCoreComponents();
  // Core components and paths are ready here.

  Component::__construct($config); // init() is being called here
  // extensions are initialized
  // controller namespace is ready
  // preloading components are loaded
}
@qiangxue qiangxue added this to the 2.0 Beta milestone Mar 17, 2014
@qiangxue
Copy link
Member

@qiangxue qiangxue commented Mar 17, 2014

I think we can add Application::bootstrap property which takes an array of class names. During init stage of application, the bootstrap method of each class will be called. I'm using bootstrap() instead of init() because the latter is already used in classes extending Object.

@qiangxue qiangxue closed this in d2c8460 Mar 17, 2014
@alpharder
Copy link
Author

@alpharder alpharder commented Mar 17, 2014

Thanks, @qiangxue ! This is the step up

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.