Skip to content
This repository

Service manager as plugin broker #1550

Merged
merged 36 commits into from almost 2 years ago

4 participants

Matthew Weier O'Phinney Evan Coury Franz de Leon | Kelmadics Matthias Tylkowski
Matthew Weier O'Phinney
Owner

In this PR, I've refactored all components that use a plugin broker (with the exception of AMF, which is currently unstable anyways) to instead compose component-specific service managers.

This introduces Zend\ServiceManager\AbstractPluginManager, as well as a few additions and fixes to the ServiceManager implementation itself. AbstractPluginManager accomplishes the following:

  • Allows passing class names directly (a feature of the old plugin broker solution)
  • Allows passing options to get(): get($name, $options). Options are by default passed directly to the constructor.
  • Allows marking the container to either share or not share instances by default, instead of requiring passing the $shared flag when calling one of the set/add methods. (This is actually a new feature of the ServiceManager, but only currently used in plugin manager implementations.)
  • Registers an initializer, validatePlugin(), at the top of the initializer stack. This allows validating that a plugin satisfies context-specific criteria.
  • Ability to peer on another service manager; if plugins cannot be retrieved from the plugin manager, but a peer is set, it will attempt to retrieve via the peer. By default, I've specified that any plugin manager managed by the MVC service manager configuration will peer off the application service manager. This makes adding plugins a trivial matter -- simply define them as services. (This functionality is technically part of the ServiceManager implementation.

Benefits of this include:

  • Keeping all plugin information in one place, instead of across multiple classes. The plugin broker solution required both the broker as well as a loader class for each plugin type. Now both are combined in a single solution.
  • Overall, 50% less code.
  • More flexibility in attaching plugins: attach instances, factories, abstract factories, etc. Or attach them to the application SM instance, and the plugin manager will fetch from there.
  • One less API to learn. Technically, we can remove the Plugin Broker and PluginClassLocator solutions at this time.

All code has been tested, though I have not completely tested with the skeleton application at this time. When possible, I have retained configuration keys for the MVC services in order to retain compatibility with the previous betas.

Build status: http://travis-ci.org/#!/weierophinney/zf2/builds/1679619

added some commits June 18, 2012
Matthew Weier O'Phinney Add ability to peer an SM instance off another
- Added addPeeringServiceManager() method to allow peering the current
  SM instance off another in either a child or parent relationship
baf69ca
Matthew Weier O'Phinney Added ability to pull from peering managers first
- Basically, allows overriding of items configured in the SM via a
  peering manager
f9d8779
Matthew Weier O'Phinney Move creational code to methods
- Will allow overriding later in subclasses
2b4176f
Matthew Weier O'Phinney Refactored FilterChain to use ServiceManager
- Updates base ServiceManager to allow arbitrary callables as initializers
- Created context-specific ServiceManager
  - Sets up initial list of invokables, aliases, and shared status
  - Toggles sharing flag in various setters to be off by default
  - Modifies get() to allow passing options as second argument
  - Overrides createFromInvokable to pass options to constructor, if present
  - Adds initializer to ensure we have a valid filter

Basically, serves as a POC for a SM-based plugin broker.
5b20333
Matthew Weier O'Phinney Share by default
- In looking at original plugin broker implementation, sharing is the
  default. This helps reduce a lot of boilerplate.
3db3525
Matthew Weier O'Phinney Added docblocks 56a7080
Matthew Weier O'Phinney Moved common functionality to AbstractPluginManager
- AbstractPluginManager defines:
  - allowOverride as on by default
  - validatePlugin() as abstract, and __construct() adds it as an
    initializer
  - get/createFromInvokable() allow passing options for requested
    plugins
- Filter\ServiceManager now extends AbstractPluginManager, and only
  needs to define invokables, aliases, and validatePlugin()
52fab2b
Matthew Weier O'Phinney Renamed Filter\ServiceManager to Filter\FilterPluginManager 826e26f
Matthew Weier O'Phinney Fix several tests and change filter aliases
- Fixed a few tests that were failing due to usage of broker
- Realized that all previously created aliases were unnecessary, as
  canonicalization strips out all special characters and lowercases.
  Removed, and then added aliases for canonicalized classnames instead
  (which allows pulling filters by class name).
31d06c1
Matthew Weier O'Phinney Refactor Filter\Inflector to use FilterPluginManager 0d5290c
Matthew Weier O'Phinney Removed Zend\Filter\Input
- Obsoleted by Zend_Filter_Input
85b98c5
Matthew Weier O'Phinney Refactored StaticFilter to use FilterPluginManager
- Identified another feature for PluginManager approach -- ability to unregister
  an instance after the fact and/or mark as not shared after registered.
bb2f2f9
Matthew Weier O'Phinney Added way to retrieve by class name
- If the plugin service does not exist, and it's a class name, add it as
  an invokable
- Allows us to remove any aliases for class names!
3493941
Matthew Weier O'Phinney Ensured all StaticFilter functionality works with FilterPluginManager
- setService($name, null) effectively removes a service by that name
- Added test to ensure above works as expected
fe09452
Matthew Weier O'Phinney Refactored Validator to use AbstractPluginManager
- Removed ValidatorLoader and ValidatorBroker
- Added ValidatorPluginManager
- Ensured all tests continue to pass
2c19dae
Matthew Weier O'Phinney Refactored Log to use AbstractPluginManager
- Removed WriterBroker and WriterLoader
- Added WriterPluginManager
- Modified Logger to use WriterPluginManager
- Overrode setService() in AbstractPluginManager in order to validate
  the service before registering it.
bd72410
Matthew Weier O'Phinney Only validate a service if not null
- in order to allow unsetting a service instance
a6cb337
Matthew Weier O'Phinney Refactored Barcode to use AbstractPluginManager
- Removed ObjectBroker, ObjectLoader, RendererBroker, and RendererLoader
- Added ObjectPluginManager and RendererPluginManager
- Refactored Barcode to use above plugin managers
5f60cb1
Matthew Weier O'Phinney Fix options in Filter\Inflector
- Were still referencing pluginBroker instead of pluginManager
- Also removed import for broker
57b4e96
Matthew Weier O'Phinney Refactored Crypt to use AbstractPluginManager
- Removed SymmectricLoader, SymmectricBroker, PaddingLoader, and
  PaddingBroker
- Added SymmetricPluginManager and PaddingPluginManager
- Refactored Symmetric\Mcrypt to use PaddingPluginManager
- Refactored BlockCipher to use SymmetricPluginManager
- Ensured all tests pass
d958774
Matthew Weier O'Phinney Refactored Mail to use AbstractPluginManager
- Removed Protocol\SmtpBroker and Protocol\SmtpLoader
- Added Protocol\SmtpPluginManager
- Refactored Transport\Smtp to use Protocol\SmtpPluginManager
- Ensured all tests pass
aabc30b
Matthew Weier O'Phinney Refactored Math\BigInteger to use AbstractPluginManager
- Removed AdapterLoader and AdapterBroker
- Added AdapterPluginManager
- Refactored BigInteger to use AdapterPluginManager
- Ensured all tests pass
662163c
Matthew Weier O'Phinney Refactored Serializer to use AbstractPluginManager
- Removed AdapterLoader and AdapterBroker
- Added AdapterPluginManager
- Refactored Serializer to use AdapterPluginManager
- Ensured all tests pass
869cd15
Matthew Weier O'Phinney Refactored Tag\Cloud to use AbstractPluginManager
- Removed Cloud\DecoratorBroker and Cloud\DecoratorLoader
- Added Cloud\DecoratorPluginManager
- Refactored Cloud to use Cloud\DecoratorPluginManager
- Ensured all tests pass
8cc93db
Matthew Weier O'Phinney Refactored Markup to use AbstractPluginManager
- Removed ParserLoader, ParserBroker, RendererLoader, and RendererBroker
- Added ParserPluginManager and RendererPluginManager
- Refactored Markup to use ParserPluginManager and RendererPluginManager
- Ensured all tests pass
354849d
Matthew Weier O'Phinney Refactored Paginator to use AbstractPluginManager
- Removed AdapterLoader, AdapterBroker, ScrollingStyleLoader, and
  ScrollingStyleBroker
- Added AdapterPluginManager and ScrollingStylePluginManager
- Refactored Paginator to use AdapterPluginManager and
  ScrollingStylePluginManager
- Modified array adapter to make constructor parameter optional
- Fixed trailing ';' issue in null adapter
- Ensured all tests pass
ca4eb70
Matthew Weier O'Phinney Refactored Cache to use AbstractPluginManager
- Removed PatternBroker, PatternLoader, AdapterBroker, AdapterLoader,
  PluginBroker and PluginManager
- Added PatternPluginManager, AdapterPluginManager, and PluginManager
- Refactored PatternFactory to use PatternPluginManager
- Refactored StorageFactory to use AdapterPluginManager and PluginManager
- Renamed TagableInterface to TaggableInterface (grammar correction), and
  corrected all adapters that use it
- Various CS fixes as they were encountered
- Ensured all tests pass
cdc9c94
Matthew Weier O'Phinney Refactored View to use AbstractPluginManager
- Helper management
  - Removed HelperLoader and HelperBroker
  - Created HelperPluginManager
  - Refactored PhpRenderer to use HelperPluginManager
- Helpers
  - Removed Navigation\HelperLoader, and replaced with Navigatin\PluginManager
  - Refactored Navigation to use a PluginManager instead of HelperLoader +
    internal registry
  - Fixed HeadLink and HeadMeta helpers; don't look for Pluggable interface, but
    instead duck type on plugin() method
- Forms
  - changed Form HelperLoader to a SM configuration object
  - duck type on plugin() instead of type check on Pluggable
- Refactored Mvc\View\ViewManager to remove references to HelperLoader and
  rename HelperBroker to HelperManager; kept original alias for ViewHelperBroker
  for migration. Moved all plugin mapping to helper manager configuration.
- Ensured all tests related to views, MVC, and forms pass
d12447e
Matthew Weier O'Phinney Refactored Mvc\Controller to use AbstractPluginManager
- Removed PluginBroker and PluginLoader
- Added PluginManager
- Refactored ActionController and RestfulController to use PluginManager
- Removed ControllerPluginLoaderFactory and ControllerPluginBrokerFactory
- Added ControllerPluginManagerFactory (and aliased it to ControllerPluginBroker
  for migration)
- Ensured all MVC and ModuleManager tests pass
f55c340
Matthew Weier O'Phinney Better capabilities surrounding sharing
- Added flag "sharedByDefault" to ServiceManager implementation, set to
  true by default
- Disabling the flag disables storing created instances for re-use
- Used with a variety of components: Cache, Crypt, Paginator, and the
  static variants of Filter and Validator
- Cannot re-set the flag if allowOverride is false
9af497e
Matthew Weier O'Phinney Refactored Mvc\Router to use AbstractPluginManager
- Removed RouteBroker
- Created RoutePluginManager; does not share by default, and overrides
  createFromInvokable() to create using route class' factory methods.
- Refactored SimpleRouteStack, TreeRouteStack, and Part route to use
  RoutePluginManager, and to have config key "route_plugins" instead of
  "route_broker"
- Ensured all tests pass
8efb5f7
Matthew Weier O'Phinney Cleanup
- Ensured all file and class level docblocks are correct
- Removed all extraneous import statements
- Ensured @throws and property annotations are correct
2a5adee
Evan Coury
Collaborator

Review in progress.

Ben Scholzen DASPRiD referenced this pull request June 24, 2012
Merged

Feature/i18n #1585

and others added some commits June 25, 2012
Matthew Weier O'Phinney [zen-56][#1550] pull from peering managers first
- Necessary to allow overriding a plugin; reported by Evan Coury
ce7ac36
Matthew Weier O'Phinney [zen-56][#1550] Test for setPluginManager instead of Pluggable
- Altered ControllerLoaderFactory's initializers to test for
  method_exists($instance, 'setPluginManager') instead of the Pluggable
  interface, and then to call setPluginManager() instead of setBroker()
717bac3
Evan Coury Use HelperManager in ViewManager
- Also set aliases for the short names so overrides work
- Cleaned up some trailing whitespace
- Side note: I think we might be going overboard with the Manager
  suffix... just sayin'.
18331da
Matthew Weier O'Phinney [zen-56][#1550] Do not clone controller plugin manager
- Leads to odd issues, due to duplicate registries
6f87c33
Evan Coury EvanDotPro merged commit 6f87c33 into from June 25, 2012
Evan Coury EvanDotPro closed this June 25, 2012
Deleted user Unknown referenced this pull request from a commit June 25, 2012
Matthew Weier O'Phinney [zen-56][#1550] pull from peering managers first
- Necessary to allow overriding a plugin; reported by Evan Coury
afefb6a
Deleted user Unknown referenced this pull request from a commit June 25, 2012
Matthew Weier O'Phinney [zen-56][#1550] Test for setPluginManager instead of Pluggable
- Altered ControllerLoaderFactory's initializers to test for
  method_exists($instance, 'setPluginManager') instead of the Pluggable
  interface, and then to call setPluginManager() instead of setBroker()
08ecdbe
Deleted user Unknown referenced this pull request from a commit June 25, 2012
Matthew Weier O'Phinney [zen-56][#1550] Do not clone controller plugin manager
- Leads to odd issues, due to duplicate registries
653e0ad
Matthias Tylkowski

Is there a reason why $this->creationOptions is set two lines before and then reset in this line? Doesn't this make the whole $options parameter useless as it's not used in this function?

Yes, there's a very good reason for it.

$creationOptions is specific to the AbstractPluginManager, and the $options does not exist in the parent ServiceManager definition. What we're doing here is setting the state so that when one of the various creation methods (createFromInvokable, createFromFactory, etc.) is invoked, they are present; those methods then use them. Once we've finished creating our instance, however, we need to reset the state so that if a later call to get() is made without an $options argument, the plugin manager will not use them.

Franz de Leon | Kelmadics

Matthew, I have always been wondering why the creation options argument was removed in the main service manager? Sometimes there are cases when i want to pass arguments via constructor without extending the abstractpluginmanager.

That very same issue also made me think about adding a new functionality for the Servicemanager called 'constructibles' that will have the same functionality as having to have arguments injected to objects via constructors. Although one may argue that this may be anti IOC but hey if we are implementing constructor injection in AbstractPluginManager, why not just have it for the main SM?

If you are interested i created a prototype for (*sorry if this should be another thread)
https://github.com/franz-deleon/zf2/blob/feature/constructables-1.0/library/Zend/ServiceManager/ServiceManager.php#L1064:

@franz-deleon The creation options were never part of the main service manager. Essentially, if you want to have service-specific options, you should create a new service factory that pulls options from configuration or defines those options in the factory itself.

When it comes to plugins, however, we often want (a) multiple instances, and (b) different behavior per-instance -- which is why we added creation options to the AbstractPluginManager definition.

@weierophinney
you should create a new service factory that pulls options from configuration or defines those options in the factory itself.
I guess the beauty of it is it forces the programmer to abide by the standards or what is considered right.

Although sometimes i am just lazy to create extra classes for something like below and still have the SM handle it:

new Car('red')
vs

$car = new Car();
$car->setColor('red')->create();

Thanks for the info and it enlightens me and makes much more sense now why things are designed the way it is.

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

Showing 36 unique commits by 2 authors.

Jun 21, 2012
Matthew Weier O'Phinney Add ability to peer an SM instance off another
- Added addPeeringServiceManager() method to allow peering the current
  SM instance off another in either a child or parent relationship
baf69ca
Matthew Weier O'Phinney Added ability to pull from peering managers first
- Basically, allows overriding of items configured in the SM via a
  peering manager
f9d8779
Matthew Weier O'Phinney Move creational code to methods
- Will allow overriding later in subclasses
2b4176f
Matthew Weier O'Phinney Refactored FilterChain to use ServiceManager
- Updates base ServiceManager to allow arbitrary callables as initializers
- Created context-specific ServiceManager
  - Sets up initial list of invokables, aliases, and shared status
  - Toggles sharing flag in various setters to be off by default
  - Modifies get() to allow passing options as second argument
  - Overrides createFromInvokable to pass options to constructor, if present
  - Adds initializer to ensure we have a valid filter

Basically, serves as a POC for a SM-based plugin broker.
5b20333
Matthew Weier O'Phinney Share by default
- In looking at original plugin broker implementation, sharing is the
  default. This helps reduce a lot of boilerplate.
3db3525
Matthew Weier O'Phinney Added docblocks 56a7080
Matthew Weier O'Phinney Moved common functionality to AbstractPluginManager
- AbstractPluginManager defines:
  - allowOverride as on by default
  - validatePlugin() as abstract, and __construct() adds it as an
    initializer
  - get/createFromInvokable() allow passing options for requested
    plugins
- Filter\ServiceManager now extends AbstractPluginManager, and only
  needs to define invokables, aliases, and validatePlugin()
52fab2b
Matthew Weier O'Phinney Renamed Filter\ServiceManager to Filter\FilterPluginManager 826e26f
Matthew Weier O'Phinney Fix several tests and change filter aliases
- Fixed a few tests that were failing due to usage of broker
- Realized that all previously created aliases were unnecessary, as
  canonicalization strips out all special characters and lowercases.
  Removed, and then added aliases for canonicalized classnames instead
  (which allows pulling filters by class name).
31d06c1
Matthew Weier O'Phinney Refactor Filter\Inflector to use FilterPluginManager 0d5290c
Matthew Weier O'Phinney Removed Zend\Filter\Input
- Obsoleted by Zend_Filter_Input
85b98c5
Matthew Weier O'Phinney Refactored StaticFilter to use FilterPluginManager
- Identified another feature for PluginManager approach -- ability to unregister
  an instance after the fact and/or mark as not shared after registered.
bb2f2f9
Matthew Weier O'Phinney Added way to retrieve by class name
- If the plugin service does not exist, and it's a class name, add it as
  an invokable
- Allows us to remove any aliases for class names!
3493941
Matthew Weier O'Phinney Ensured all StaticFilter functionality works with FilterPluginManager
- setService($name, null) effectively removes a service by that name
- Added test to ensure above works as expected
fe09452
Matthew Weier O'Phinney Refactored Validator to use AbstractPluginManager
- Removed ValidatorLoader and ValidatorBroker
- Added ValidatorPluginManager
- Ensured all tests continue to pass
2c19dae
Matthew Weier O'Phinney Refactored Log to use AbstractPluginManager
- Removed WriterBroker and WriterLoader
- Added WriterPluginManager
- Modified Logger to use WriterPluginManager
- Overrode setService() in AbstractPluginManager in order to validate
  the service before registering it.
bd72410
Matthew Weier O'Phinney Only validate a service if not null
- in order to allow unsetting a service instance
a6cb337
Matthew Weier O'Phinney Refactored Barcode to use AbstractPluginManager
- Removed ObjectBroker, ObjectLoader, RendererBroker, and RendererLoader
- Added ObjectPluginManager and RendererPluginManager
- Refactored Barcode to use above plugin managers
5f60cb1
Matthew Weier O'Phinney Fix options in Filter\Inflector
- Were still referencing pluginBroker instead of pluginManager
- Also removed import for broker
57b4e96
Matthew Weier O'Phinney Refactored Crypt to use AbstractPluginManager
- Removed SymmectricLoader, SymmectricBroker, PaddingLoader, and
  PaddingBroker
- Added SymmetricPluginManager and PaddingPluginManager
- Refactored Symmetric\Mcrypt to use PaddingPluginManager
- Refactored BlockCipher to use SymmetricPluginManager
- Ensured all tests pass
d958774
Matthew Weier O'Phinney Refactored Mail to use AbstractPluginManager
- Removed Protocol\SmtpBroker and Protocol\SmtpLoader
- Added Protocol\SmtpPluginManager
- Refactored Transport\Smtp to use Protocol\SmtpPluginManager
- Ensured all tests pass
aabc30b
Matthew Weier O'Phinney Refactored Math\BigInteger to use AbstractPluginManager
- Removed AdapterLoader and AdapterBroker
- Added AdapterPluginManager
- Refactored BigInteger to use AdapterPluginManager
- Ensured all tests pass
662163c
Matthew Weier O'Phinney Refactored Serializer to use AbstractPluginManager
- Removed AdapterLoader and AdapterBroker
- Added AdapterPluginManager
- Refactored Serializer to use AdapterPluginManager
- Ensured all tests pass
869cd15
Matthew Weier O'Phinney Refactored Tag\Cloud to use AbstractPluginManager
- Removed Cloud\DecoratorBroker and Cloud\DecoratorLoader
- Added Cloud\DecoratorPluginManager
- Refactored Cloud to use Cloud\DecoratorPluginManager
- Ensured all tests pass
8cc93db
Matthew Weier O'Phinney Refactored Markup to use AbstractPluginManager
- Removed ParserLoader, ParserBroker, RendererLoader, and RendererBroker
- Added ParserPluginManager and RendererPluginManager
- Refactored Markup to use ParserPluginManager and RendererPluginManager
- Ensured all tests pass
354849d
Matthew Weier O'Phinney Refactored Paginator to use AbstractPluginManager
- Removed AdapterLoader, AdapterBroker, ScrollingStyleLoader, and
  ScrollingStyleBroker
- Added AdapterPluginManager and ScrollingStylePluginManager
- Refactored Paginator to use AdapterPluginManager and
  ScrollingStylePluginManager
- Modified array adapter to make constructor parameter optional
- Fixed trailing ';' issue in null adapter
- Ensured all tests pass
ca4eb70
Matthew Weier O'Phinney Refactored Cache to use AbstractPluginManager
- Removed PatternBroker, PatternLoader, AdapterBroker, AdapterLoader,
  PluginBroker and PluginManager
- Added PatternPluginManager, AdapterPluginManager, and PluginManager
- Refactored PatternFactory to use PatternPluginManager
- Refactored StorageFactory to use AdapterPluginManager and PluginManager
- Renamed TagableInterface to TaggableInterface (grammar correction), and
  corrected all adapters that use it
- Various CS fixes as they were encountered
- Ensured all tests pass
cdc9c94
Matthew Weier O'Phinney Refactored View to use AbstractPluginManager
- Helper management
  - Removed HelperLoader and HelperBroker
  - Created HelperPluginManager
  - Refactored PhpRenderer to use HelperPluginManager
- Helpers
  - Removed Navigation\HelperLoader, and replaced with Navigatin\PluginManager
  - Refactored Navigation to use a PluginManager instead of HelperLoader +
    internal registry
  - Fixed HeadLink and HeadMeta helpers; don't look for Pluggable interface, but
    instead duck type on plugin() method
- Forms
  - changed Form HelperLoader to a SM configuration object
  - duck type on plugin() instead of type check on Pluggable
- Refactored Mvc\View\ViewManager to remove references to HelperLoader and
  rename HelperBroker to HelperManager; kept original alias for ViewHelperBroker
  for migration. Moved all plugin mapping to helper manager configuration.
- Ensured all tests related to views, MVC, and forms pass
d12447e
Matthew Weier O'Phinney Refactored Mvc\Controller to use AbstractPluginManager
- Removed PluginBroker and PluginLoader
- Added PluginManager
- Refactored ActionController and RestfulController to use PluginManager
- Removed ControllerPluginLoaderFactory and ControllerPluginBrokerFactory
- Added ControllerPluginManagerFactory (and aliased it to ControllerPluginBroker
  for migration)
- Ensured all MVC and ModuleManager tests pass
f55c340
Matthew Weier O'Phinney Better capabilities surrounding sharing
- Added flag "sharedByDefault" to ServiceManager implementation, set to
  true by default
- Disabling the flag disables storing created instances for re-use
- Used with a variety of components: Cache, Crypt, Paginator, and the
  static variants of Filter and Validator
- Cannot re-set the flag if allowOverride is false
9af497e
Jun 22, 2012
Matthew Weier O'Phinney Refactored Mvc\Router to use AbstractPluginManager
- Removed RouteBroker
- Created RoutePluginManager; does not share by default, and overrides
  createFromInvokable() to create using route class' factory methods.
- Refactored SimpleRouteStack, TreeRouteStack, and Part route to use
  RoutePluginManager, and to have config key "route_plugins" instead of
  "route_broker"
- Ensured all tests pass
8efb5f7
Matthew Weier O'Phinney Cleanup
- Ensured all file and class level docblocks are correct
- Removed all extraneous import statements
- Ensured @throws and property annotations are correct
2a5adee
Jun 25, 2012
Matthew Weier O'Phinney [zen-56][#1550] pull from peering managers first
- Necessary to allow overriding a plugin; reported by Evan Coury
ce7ac36
Matthew Weier O'Phinney [zen-56][#1550] Test for setPluginManager instead of Pluggable
- Altered ControllerLoaderFactory's initializers to test for
  method_exists($instance, 'setPluginManager') instead of the Pluggable
  interface, and then to call setPluginManager() instead of setBroker()
717bac3
Evan Coury Use HelperManager in ViewManager
- Also set aliases for the short names so overrides work
- Cleaned up some trailing whitespace
- Side note: I think we might be going overboard with the Manager
  suffix... just sayin'.
18331da
Matthew Weier O'Phinney [zen-56][#1550] Do not clone controller plugin manager
- Leads to odd issues, due to duplicate registries
6f87c33
Something went wrong with that request. Please try again.