-
-
Notifications
You must be signed in to change notification settings - Fork 59
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
Remove ServiceManager
inheritance for AbstractPluginManager
#179
Remove ServiceManager
inheritance for AbstractPluginManager
#179
Conversation
* @group mutation | ||
* @covers \Laminas\ServiceManager\ServiceManager::mapLazyService | ||
*/ | ||
public function testCanMapLazyServices(): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this test to the ServiceManager
specific tests as this is used for both AbstractPluginManager
AND ServiceManager
.
I could've checked the container instance and marked as skipped but since there is already a dedicated test class, I moved it.
bc629f5
to
c11f339
Compare
@boesing ok , I can do that 👍 , I may need summary which part that need update |
04edafb
to
e81b2c3
Compare
Partly solves #44 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My only major problem with this patch is the addition of #configure()
on interfaces that are designed for container consumption, rather than configuration.
Configuration of a container can happen on concrete instances, while the ContainerInterface
, ServiceLocatorInterface
and PluginManagerInterface
interfaces should be read-only, without any assumption that they might be configurable.
Heck, they may be dumped/generated code.
Its use case might have been related to how container or various plugin managers were configured after creation in module manager/mvc events. I am for making it internal implementation detail and removing from public interface. |
|
@Xerkus @Ocramius I'd be up for a read-only container with v5. Given the fact that v4 to the end of Q1 is already tough with all the migration paths, I'd prefer not being too complex here. Keeping the old methods is mostly due to BC compat but I am fine with dropping configure from the Interface. WDYT? |
Dropping from the interface(s) is sufficient for me, for now 👍 |
6548c34
to
e9c797a
Compare
e9c797a
to
f445aa9
Compare
ServiceManager
inheritance for AbstractPluginManager
ServiceManager
inheritance for AbstractPluginManager
f445aa9
to
8f92678
Compare
…e plugins This removes the inheritance of the `ServiceManager` and marks the `ServiceManager` `final` in a soft state. Signed-off-by: Maximilian Bösing <[email protected]>
Signed-off-by: Maximilian Bösing <[email protected]>
Signed-off-by: Maximilian Bösing <[email protected]>
8f92678
to
4845306
Compare
Signed-off-by: Maximilian Bösing <[email protected]>
Signed-off-by: Maximilian Bösing <[email protected]>
This comment was marked as outdated.
This comment was marked as outdated.
Signed-off-by: Maximilian Bösing <[email protected]>
381e588
to
827be21
Compare
composer.json
Outdated
"phpbench/phpbench": "^1.2.7", | ||
"phpunit/phpunit": "^9.5.26", | ||
"psalm/plugin-phpunit": "^0.18.0", | ||
"symfony/console": "^6.0", | ||
"vimeo/psalm": "^5.0.0" | ||
"vimeo/psalm": "5.x-dev" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- needs to be switched back once psalm releases the next minor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall,I like this approach. Composing a ServiceManager
inside the AbstractPluginManager
removes a lot of duplication, while simultaneously removing the inheritance. Having an interface means we can use that as the type instead of an abstract class, which also makes me happy. And the psalm shapes in the ServiceManager
provide valuable documentation of expectations.
My only concern/issue is that I don't recall the the rationale for deprecating/removing the ConfigInterface
and Config
class. I recognize that we can use Psalm annotations to provide shapes for valid data, but that seems more likely to lead to issues at runtime where the shapes cannot be verified/validated. That said, I won't block approval on that; just wish I could remember what the arguments were around this.
src/PluginManagerInterface.php
Outdated
public function has(string $id): bool; | ||
|
||
/** | ||
* @template TRequestedInstance extends InstanceType | ||
* @psalm-param class-string<TRequestedInstance>|string $id Service name of plugin to retrieve. | ||
* @psalm-return ($id is class-string ? TRequestedInstance : InstanceType) | ||
* @throws Exception\ServiceNotFoundException If the manager does not have | ||
* a service definition for the instance, and the service is not | ||
* auto-invokable. | ||
* @throws InvalidServiceException If the plugin created is invalid for the | ||
* plugin context. | ||
*/ | ||
public function get(string $id): mixed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since ServiceLocatorInterface
already extends ContainerInterface
, should these really be defined here?
I can understand defining get()
so we can add the additional annotations, but at the very least, has()
feels superfluous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yah, has
is superfluous indeed.
I guess I've added it to also add some psalm-assert
on it to provide information of what will be returned from get
. But since has
actually does no validation at all, it would provide false information and thus we can safely drop it here.
I don't see any value for that interface or the Config. The interface itself was not used anywhere and the container.php <?php
use Laminas\ServiceManager\Config;
use Laminas\ServiceManager\ServiceManager;
require_once __DIR__ . '/../vendor/autoload.php';
// Load configuration
$config = require __DIR__ . '/config.php';
// Build container
$container = new ServiceManager();
(new Config($config['dependencies']))->configureServiceManager($container);
// Inject config
$container->setService('Config', $config);
// Make container writable since we want to overwrite even existing alias for config
$container->setAllowOverride(true);
$container->setAlias('config', 'Config');
$container->setAllowOverride(false);
return $container; The laminas-modulemanager seems to provide support for the So its just a dangling class mostly used to have a value-object of the config which wasnt properly validated at runtime and didn't provide any type until 3.9.0 which was 11 years after the initial creation of the interface. Thats why I think we can safely drop it and let upstream projects actually return the array structure while using psalm + psalm-type to have proper type validation: before <?php
namespace MyModule;
use Laminas\ModuleManager\Feature\ServiceProviderInterface;
use Laminas\ServiceManager\Config;
use Laminas\ServiceManager\Factory\InvokableFactory;
final class Module implements ServiceProviderInterface
{
public function getServiceConfig(): Config
{
return new Config([
'factories' => [
MyModuleService::class => InvokableFactory::class,
],
]);
}
} after <?php
namespace MyModule;
use Laminas\ModuleManager\Feature\ServiceProviderInterface;
use Laminas\ServiceManager\Factory\InvokableFactory;
use Laminas\ServiceManager\ServiceManager;
/** @psalm-import-type ServiceManagerConfiguration from ServiceManager */
final class Module implements ServiceProviderInterface
{
/**
* @return ServiceManagerConfiguration
*/
public function getServiceConfig(): array
{
return [
'factories' => [
MyModuleService::class => InvokableFactory::class,
],
];
}
} However, I am open to keep the Should we create an RFC for this? I can restore the |
@boesing Thanks for that summary! When I consider that the majority of the time, we're passing an array to either the |
Signed-off-by: Maximilian Bösing <[email protected]>
@samsonasik I guess I've finished the work here, so I can provide a lil summary:
Not 100% sure if that is already everything but I guess at least for this PR that should reflect almost all changes. |
@boesing Thank you for the summary, I will try what I can do 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚢
1ee6810
to
d38a600
Compare
Signed-off-by: Maximilian Bösing <[email protected]>
d38a600
to
8f14d75
Compare
Signed-off-by: Maximilian Bösing <[email protected]>
Description
This is a PoC of how the plugin manager could work without inheriting from the
ServiceManager
.With this PoC, I've also modified
ServiceManager
to returnmixed
as thats actually the case already. Nothing in this component verifies that something isobject
. We do have soft-types for factories to only returnobject
but in fact, they can returnmixed
anyways.Since the
AbstractPluginManager
does not require an$instanceOf
value and thus, can also returnmixed
in case it is not set, I think this change makes sense until we decide to go the same route as symfony does. Since that decision has not yet been made, I'd prefer to skip that. I'm open to create an RFC for this and bring it to the next TSC if some1 wants to further discuss this.Please NOTE that I also:
ServiceManager
and/orAbstractPluginManager
laminas/laminas-servicemanager-migration
rector rules once we finished with adding all the missing types?)ServiceManagerConfigurationType
(still compatible but more strict)TODOS:
ConfigInterface
andConfig
as deprecated in v3ConfigInterface
toServiceManager
in a redundant way (in v3) so that upstream projects can already switchServiceManager
as@final
in v3class-string<callable(ContainerInterface,string,array|null):mixed>