# Known Bugs: - Bug ->go or ->visit causes actions which have Args or CaptureArgs called twice when called via ->go or ->visit. Test app: http://github.com/bobtfish/catalyst-app-bug-go_chain/tree/master # Compatibility warnings to add: - $self->config should warn as config should only ever be called as a class method (TESTS). # Proposed functionality / feature additions: ## Log setup needs to be less lame So Catalyst::Plugin::Log::* can die in a fire. Having $c->log_class would be a good start. kane volunteered to do some of this. Simple example: Catalyst::Plugin::Log::Colorful should just be a subclass of Catalyst::Log, no ::Plugin:: needed. See also: Catalyst::Plugin::Log::Dispatch and http://github.com/willert/catalyst-plugin-log4perl-simple/tree # REFACTORING ## The horrible hack for plugin setup - replacing it: * Have a look at the Devel::REPL BEFORE_PLUGIN stuff I wonder if what we need is that combined with plugins-as-roles ## App / ctx split: NOTE - these are notes that t0m thought up after doing back compat for catalyst_component_class, may be inaccurate, wrong or missing things bug mst (at least) to correct before trying more than the first 2 steps. Please knock yourself out on the first two however :) - Eliminate actions in MyApp from the main test suite - Uncomment warning in C::C::register_action_methods, add tests it works by mocking out the logging.. - Remove MyApp @ISA controller (ask metaclass if it has attributes, and if so you need back compat :/) - Make Catalyst::Context, move the per request stuff in there, handles from main app class to delegate - Make an instance of the app class which is a global variable - Make new instance of the context class, not the app class per-request - Remove the components as class data, move to instance data on the app class (you probably have to do this for _all_ the class data, good luck!) - Make it possible for users to spin up different instances of the app class (with different config etc each) - Profit! (Things like changing the complete app config per vhost, i.e. writing a config loader / app class role which dispatches per vhost to differently configured apps is piss easy) ## GSOC ### Next large steps, planned: For all components that have been discovered, in whatever way, we create a service: - that's a catalyst component service - which is basically just a constructor injection - except the constructor name is COMPONENT - and we're "implicitly" passing along some constructor args - Lifecycle => Singleton - We make a 'components' sub container in the main container. - This gets the ConstructorInjection COMPONENT services, as model_Foo. - Lifecycle of these services is Singleton - This simplifies the code for MyApp->components, as it need only list one sub-container - We create a second service (depending on the first one) for ACCEPT_CONTEXT - This has a custom service which calls ACCEPT_CONTEXT when the instance is fetched - Not Singleton lifecycle Note - ACCEPT_CONTEXT can be called on app values - if you have a Model::Foo, with an ACCEPT_CONTEXT and you call MyApp->model('Foo') then ACCEPT_CONTEXT gets invoked with a $c of 'MyApp' (this is not\ the normal case, but we need to preserve for compat) ### Next steps - less planned: - Creating service()-like sugar for component - Test cases for extending the container in an application. - Using the sugar added in the previous item - Test when Model::Foo depends_on Model::Bar a) configure additional services in that container - super simple container $default_container => as { more services }; class MyApp::Container extends Catalyst::Container { use Bread::Board; # Or our own sugar? method BUILD { container $self => as { service model => ...; # some constructor injection to MyApp::Model or something container Model => as { component Foo => (dependencies => ['/model']); # As per default! component Bar => (dependencies => ['/model/Foo']); # Magic! }; # Note - implementation of BB may need to be changed to support making sure existing # services actually get overridden. not sure how the default container behaves when doing that # above code would build the constructor injection as it currently does, # defaulting to the class name in the right namespace as declared by the surrounding container # as well as adding using the catalyst-specific service class } } }; let's consider the usage patterns we actually want to enable by doing the whole B::B thing what happens if i make the "per-app" service for a component life only for the duration of the request? or be instanciated every time i look up the component? (or scoping it per session, or having a block injection, or something) say you override the app service to be per-request now the wrapper for the per-request variant doesn't make sense anymore. does it? because you're only overriding one half of what has been generated automatically ah, so you have basically ended up with getting a request scoped thing to be used to construct a request scoped thing, which is pointless? Would/could you not just override the service which is actually getting looked up instead, and make it not depend on the auto-generated per-app scope service, which will then just never be built? yes, you could. but then you'd have to be aware of the distinction which is what i hoped to be a barely visible backcompat thing but which i'm afraid it won't be if we go for two actual separate services what stops the sugar we give from not just making you specify the lifecycle, and giving you the obvious name / wiring? i.e. everything looks like 'Foo', so you don't have to know COMPONENT/Foo exists my hopes of not needing any sugar at all, i guess only a couple of new lifecycles to be registered with the container - ?? ### To polish off / t0m review - + $class->container->get_sub_container('model')->make_single_default; + $class->container->get_sub_container('view')->make_single_default; get_components_names_types locate_components +# FIXME - t0m, how do you feel about this name? +# also, do you think I should draw it here, or just return the data structure? +sub get_components_names_types { + MyApp->config->{ 'Plugin::ConfigLoader' }->{ substitutions } = { +# FIXME - just till I understand how it's supposed to be done +# Made this so that COMPONENT is executed once, +# and ACCEPT_CONTEXT every call. +has instance => ( + is => 'rw', # This is ok?? +my $applevel_config = TestAppContainer->container->resolve(service => 'config')->{applevel_config}; +__PACKAGE__->config(applevel_config => 'foo'); accept_context_args - where does this come from? ### Known issues - Broken $instance->expand_modules() in setup_components and figure out later how to bring it back - expand_component_module