Closed bar closed 11 years ago
@kamisama Currently, I'm using the 3rd way to load my configs, because I want all the default ones, except for the hostname. And I don' t want to update the custom config every time I update (which could happen with the 2nd way).
This way you don' t need to exclude anything from git, and you don't alter the repo.
Another approach would be to just bootstrap requiring the CakeResque.php
and place the CakeResque::init()
call inside the App's bootstrap as an initialization process.
Any thoughts?¿
Very interesting, I'll look into it as soon as I have some time
@kamisama Thanks, I need another point of view on that :)
From what I see, the difference between #.3 and #.4 is the way the path of the config file is loaded.
Can you not achieve the same thing using #.4, but using a a relative path to your config file in bootstrap
? That way, the file can be located outside the plugin folder, and the submodule doesn't have to be modified in any way.
Right now, every time you Configure::load()
in the main bootstrap.php
, the configuration is later incorrectly merged (by default) when the plugin calls again Configure::load()
so #2, #3 or #4 can't be done.
As a bonus, #4 allows a $config
var to be passed and be used as default configuration, avoiding the Configure::load()
call.
I think I don't quite understand the question, but I'll try to elaborate more: #3 and #4 (without config file) are different:
bootstrap
file, and that file needs to be inside the plugin's domain, take a look at CakePlugin::bootstrap()
which is called by CakePlugin::load()
. It uses no config file (but a $config
var) because it is pointless to have 2 files (one with a config file, and another with the bootstrap file) when a custom setup is needed, and it can be achieved with one file. But you should be able to keep it decoupled if needed:CakePlugin::load('CakeResque', array('bootstrap' => 'my_bootstrap'));
// APP/Plugin/CakeResque/Config/my_bootstrap.php
require_once dirname(__DIR__) . DS . 'Lib' . DS . 'CakeResque.php';
Configure::load('my_cakeresque_config'); // For instance
CakeResque::init();
For that, #4 is no good when you want to keep the plugin clean and untouched (which was my goal in the first place), but the restriction of the custom bootstrap file living inside the plugin's domain is a deal breaker.
// Must be called to be able to make the next call, it needs to know the plugin.
CakePlugin::load('CakeResque');
// Loads the *default* config file
Configure::load('CakeResque.config');
// Edit configuration here as needed. Notice that the default configuration file is loaded first.
// Reload the plugin bootstrapping it so that when it detects that a configuration is already loaded, it won't reloadit.
CakePlugin::load('CakeResque', array('bootstrap' => true));
It is simple, easy and does not mess with the plugin (like #3), but... the user has to be more aware of the updates in the plugin's default configuration file so that it is up to date after updating.
Please elaborate more in your original concern if I did not answer the question, maybe an example will help :)
This is from CakePlugin::bootstrap()
:
$bootstrap = (array)$config['bootstrap'];
foreach ($bootstrap as $file) {
self::_includeFile(
$path . 'Config' . DS . $file . '.php',
$config['ignoreMissing']
);
}
I'm not 100% sure, as I didn't test it yet, but can't $file
be ../../Config/cake_resque.php
? That way, the config file lived outside the plugin, and case 3 === case 4
For #2, you're calling Configure::load('my_cakeresque_config');
Again, I have not tested it yet, but bootstrap in CakePlugin::load()
can takes a callable function. Maybe you can pass it directly ?
CakePlugin::load('CakeResque', array('bootstrap' => Configure::load('my_cakeresque_config')));
Yes, You are 100% correct. it can be a relative path, the thing is $path
is obtained from CakePlugin::path()
which returns the FS path to the plugin :/
https://github.com/cakephp/cakephp/blob/master/lib/Cake/Core/CakePlugin.php#L145
And using something like ../
in the relative path should take you everywhere you want
I confirm that using
CakePlugin::load('CakeResque', array('bootstrap' => '../../../Config/cake-resque'));
is loading the config file app/Config/cake-resque.php
.
So I guess that there's not much difference between #3 and #4
You are right! a bit weird because how it is built $path . 'Config' . DS . $file . '.php'
.
But there is still difference, in that #4 needs to replicate the plugin's bootstrap, and load the config. #3 doesn't care of the bootstrapping process, it just loads the config ;)
Yeah, to use #3 with all the default options, you still have to require
the original bootstrap file in the head of the new bootstrap file. Or is there other difference ?
That works for the #2 method :
CakePlugin::load('CakeResque', array('bootstrap' => function() { Configure::load('my_cakeresque_config'); }));
Exactly, it would be the same. but the user should take into the account the require an some other magic which may be included in a future bootstrapping.
Nicely pulled, I didn't wanted to end up calling call_user_func_array() to speed up every request, but it is very doable :)
You, would still need to require CakeResque and load it, though.
So:
CakePlugin::load('CakeResque', array('bootstrap' => function() { Configure::load('my_cakeresque_config'); }));
CakePlugin::load('CakeResque', array('bootstrap' => '../../../Config/cake-resque'));
with require
I guess that PR can be closed ? Or is there additional features I skipped ?
require
and the CakeResque:::init()
if you put it that way, cause you have to move the plugin's bootstrap process to the abstract function too, if you load the config using the bootstrapping callable.require
and the CakeResque:::init()
of course.If you think about it, the way you put it, the whole bootstrap process:
// Load configuration
Configure::load()
// Bootstrap
require
CakeResque:::init()
can be
The original #2 and #3 were meant to only "play" with the configuration part, without considering the bootstrap part, in a nutshell:
// Load configuration
Configure::load()
// Make the plugin bootstrap with that config
CakePlugin::load('CakeResque', array('bootstrap' => true));
There is also a bit of documentation/hints here https://github.com/kamisama/Cake-Resque/pull/28/files#L1R43 that may need a review.
Config documentation is pertinent. The rest of the PR, like the use of Configure
to load the configuration, doesn't seems too useful.
So you say it is better to keep the whole configuration inside the bootstrap file?
Yes. It'll be much more easier to override when calling a custom bootstrap file in CakePlugin::load()
.
You still can do it, but why bother a user that just need/want to configure the plugin, with all the bootstrapping process?¿
I think keeping the configuration inside a configuration file is cleaner/easier.
That's why CakePHP uses different files like app/Config/core.php
and app/Config/bootstrap.php
, separation of concerns. If would be sad if someone needs to copy lib/Cake/bootstrap.php
entirely to change a configuration :/
What I don't like with the separation approach is the need to call Configure::load('my_cakeresque_config');
before the CakePlugin::load()
.
Maybe you can do that:
CakePlugin::load('CakeResque', array('bootstrap' => ['../../../Config/cake-resque', 'bootstrap']));
That way, the user configuration is loaded first, then the bootstrap. Bootstrap will check if a config is already loaded, else will load the default config file.
FYI, Configure::check
doesn't seems to exists in Cake 2.2.
Yes, with the PR implementation, it doesn't matter, you can do it both ways, because the change tests for a loaded configuration first. In my case, I feel it is more natural to configure something using a Configure
call without the disadvantage of knowing bootstrapping internals.
You can pass that array to CakePlugin::load()
, it will load both bootstrap files, one inside the App, and the other inside the plugin.
But... if I understand correctly, you still need to load the configuration inside the first bootstrap file.
You are right, it can be easily ported from 2.3 and be placed inside CakeResque::loadConfig()
I'm beginning to be confused. With that PR, can we load a custom config file by using only the bootstrap
key of CakePlugin::load()
?
Yes, if you don't want to call Configure::load()
, before the CakePlugin::load()
, you need to have a $config
array with the config options, inside the bootstrap file you load, like the original #4.
CakePlugin::load('CakeResque', array('bootstrap' => '../../../my_bootstrap'));
// APP/Config/my_bootstrap.php
require_once dirname(__DIR__) . DS . 'Lib' . DS . 'CakeResque.php';
$config = array(); // Custom configuration
CakeResque::init($config);
But with this PR, it can be done with
CakePlugin::load('CakeResque', array('bootstrap' => ['../../../Config/cake-resque', 'bootstrap']));
too, right ?
Yes, but there is no point in calling CakePlugin::load()
with an array because the second file becomes unnecessary.
If you just do CakePlugin::load('CakeResque', array('bootstrap' => '../../../Config/cake-resque')):
it should be enough.
But the cake-resque file contains only the config, and not the require
, that's located in the bootstrap file, right ?
Nope, you will always need to load a config at some point. The 'bootstrap' key just requires the file, it does not load configs. That's why you used Configure
to do it before.
It would be a yes, if cake-resque
had a Configure
call inside, then the other bootstrap can have the require and init. But I understand you don't want a Configure
call.
I'm fine with having Configure inside the config file. I just don't like something like that :
Configure::load('my_cakeresque_config');
CakePlugin::load('CakeResque', array('bootstrap' => true));
I think something like this...
CakePlugin::load('CakeResque', array('bootstrap' => ['../../../Config/cake-resque', 'bootstrap']));
// APP/Config/cake-resque.php
Configure::load(´whatever_name_you_want_for_cakeresque');
// And... whatever change you want to apply here
// This should be the content of the plugin bootstrap
// APP/Plugin/CakeResque/Config/bootstrap.php
require_once dirname(__DIR__) . DS . 'Lib' . DS . 'CakeResque.php';
CakeResque::init();
That's exactly what I'm thinking :+1:
Nice! I think it will work, the only thing I don't like is managing two files :) In that case you should do this:
CakePlugin::load('CakeResque', array('bootstrap' => ['../../../Config/cake-resque', 'bootstrap']));
// APP/Config/cake-resque.php
Configure::write('CakeResque´, array(
// config here
));
But if you need the default config before manipulating it... like in #3, you will need something like
CakePlugin::load('CakeResque', array('bootstrap' => ['../../../Config/cake-resque', 'bootstrap']));
// APP/Config/cake-resque.php
Configure::load('CakeResque.config');
Configure::write('CakeResque.foo´, ´bar');
What I don't know is if the Configure::load('CakeResque.config')
will let you reach the plugin's config...
I think it should, because CakePlugin::bootstrap()
is done at the end of CakePlugin::load()
, so self::$_plugins[´CakeResque´]
will already be set, hopefully.
Why would you need the default config before manipulating it ?
So that I don't need to copy it whole every time I update the plugin. I just load the template (default conf) with the minimum confs, and then just change... 'Redis.localhost' for example.
No, you don't need to, Configure
can handle that, and merge your setting into the default one.
You can just do Configure::write('CakeResque.Redis.host', 'localhost');
in the cake-resque
file, and Configure::load()
can merge that into the default settings.
If you write something to the configuration file, the default config won't be autoloaded later because is will be "checked", remember?
And if you call Configure::load()
manually after, it will automerge using Hash::merge()
which you don't want because the settings inside the config are not 1 level deep, they have arrays of arrays some times, `'CakeResque.Queues'`` for example.
For the merge issue, a possible solution would be to remvoe the Configure
in the default config, and leave it as a simple multi dimensional array.
If a custom config exists, load it in init()
via Configure::read("CakeResque")
, then merge the returned array with the array in the default config.
Can you elaborate more on that idea? I don't quite understand what you meant by loading it in init()
via Configure::read()
and then merging the returned array with the default one.
You need to make a call to Configure
at some point inside the default config/bootstrap, an array will not suffice. When there is no custom config, you still need to load a configuration because all the Configure::read()
calls needed in CakeResque
, which I think they are the correct way to go.
I don't think it is a problem loading a template and then modifying it when you need to, it can all be done with 1 extra line, in the custom bootstrap for example.
You can pass an array to init()
and it will be loaded but you have a problem every time you "merge", it doesn't matter if its in the App or in the Plugin, the problem is the merge, which is not controlled, neither an array_merge()
, an array_merge_recursive()
or even a Hash::merge()
, because you don't have control.
As I said, if you merge a key with an array inside, you will not modify the content of the first one, but append a new array, or you will end up replacing the whole key, when you only need to replace one internal value from the key. It all depends on the "merge" function you use :(
=> array_merge_recursive()
// CakeResque/Config/custom.php Configure::write('CakeResque.Redis.host', 'localhost');
Then you can merge that with the default config with
// Reading the custom config
$r = Configure::read('CakeResque');
require './default-config.php';
// $config variables holding all the default config is visible
// Merge it with the custom config
Configure::write(array_merge_recursive($config, $r);
I don't pass anything to init(), merging is done by bootstrap before init()
Boostraping role will be to collect the various config and merge them.
The concept is:
There are many ways to configure the plugin: