Skip to content
This repository has been archived by the owner on Feb 6, 2020. It is now read-only.

Repeated AbstractFactory may occur in ServiceManager. #106

Closed
wants to merge 3 commits into from
Closed

Repeated AbstractFactory may occur in ServiceManager. #106

wants to merge 3 commits into from

Conversation

Moln
Copy link
Contributor

@Moln Moln commented Mar 31, 2016

See #104

@Ocramius
Copy link
Member

Ocramius commented Jun 1, 2016

Needs a test case before being applied.

@Ocramius Ocramius removed their assignment Jun 1, 2016
@Moln
Copy link
Contributor Author

Moln commented Jun 2, 2016

Added a unit test.

@samsonasik
Copy link
Contributor

ping @Ocramius

@Ocramius
Copy link
Member

I just realized that this change is incorrect.

Following code is perfectly legit, for example:

$abstractFactory1 = new MyConfiguredAbstractFactory($config1);
$abstractFactory2 = new MyConfiguredAbstractFactory($config2);

$sm = new ServiceManager([
    'abstract_factories' => [
        $abstractFactory1,
        $abstractFactory2,
    ],
]);

This scenario seems legit to me, and is actually even used within stuff like DoctrineModule, now that I look closer.

I think the key used to store the factory internally should be based on spl_object_hash() instead.

A test for this scenario is also needed, IMO...

$serviceManager->addAbstractFactory(CallOnlyOnceAbstractFactory::class);
$serviceManager->has(stdClass::class);

$this->assertEquals(1, CallOnlyOnceAbstractFactory::getCallTimes());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be 2.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new test with the same instance of CallOnlyOnceAbstractFactory should be provided. In that scenario, only one factory should remain.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And even there, strong reasoning should be given as to why a duplicate abstract factory is actually a problem...

@Moln
Copy link
Contributor Author

Moln commented Jun 22, 2016

Ocramius is right.
It is my new pull.

ServiceManager:

  1. The key used spl_object_hash() instead.
  2. Add $cachedAbstractFactories property for cached some instances.

Unit test:

  1. Remove testCallOnlyOnceWithMultipleIdenticalAbstractFactory
  2. Add testCallTwiceWithDifferentInstanceAbstractFactories and testCallOnlyOnceWithSameInstanceAbstractFactory.

@Ocramius
Copy link
Member

Ok, now that the patch is correct (and sorry if it feels like I'm dragging you around, I really get to check this stuff when it pops up in my inbox): what kind of problem does #104 cause? Is it just a performance issue?

Assuming idempotent factories (big assumptions, so I might be wrong here), I don't see a problem with having two factories referencing the same instance inside the ServiceManager...

@Moln
Copy link
Contributor Author

Moln commented Jul 1, 2016

I thought for a while. May be I am too sensitive to performance.
Yes, it a performance issue. May be a very little performance impact.

At that time I wrote two ZF modules (Module A & Module B). They all have the same configuration.

'service_manager' => array(
 'abstract_factories' => array(
    'Zend\Db\Adapter\AdapterAbstractServiceFactory',
    'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
    '...',
 ),
),

I just want to get another service, but call every AbstractFactory::canCreateServiceWithName() twice. I just feel no need.

Now this is another solution.

class Module
{
    public function init(ModuleManager $manager)
    {
        $manager->getEventManager()->attach(ModuleEvent::EVENT_MERGE_CONFIG, function (ModuleEvent $event) {
            /** @var \Zend\ModuleManager\Listener\ConfigListener $configListener */
            $configListener =$event->getParam('configListener');
            $configs = $configListener->getMergedConfig(false);

            $configs['service_manager']['abstract_factories'] =
                array_unique($configs['service_manager']['abstract_factories']);

            $configListener->setMergedConfig($configs);
        });
    }
}

😄 😄

@snapshotpl
Copy link
Contributor

It can be problem when canCreate will be more expensive and will return false.

@Moln
Copy link
Contributor Author

Moln commented Jul 2, 2016

Or may be it is zend-modulemanager or zend-mvc issue, not zend-servicemanager.

@weierophinney weierophinney added this to the 3.2.0 milestone Sep 1, 2016
@weierophinney weierophinney self-assigned this Sep 1, 2016
@weierophinney
Copy link
Member

Assigning to 3.2.0 release, as the feature is technically new behavior.

weierophinney added a commit that referenced this pull request Sep 1, 2016
Repeated AbstractFactory may occur in ServiceManager.

Conflicts:
	src/ServiceManager.php
weierophinney added a commit that referenced this pull request Sep 1, 2016
weierophinney added a commit that referenced this pull request Sep 1, 2016
@weierophinney
Copy link
Member

Merged to develop for release with 3.2.0

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants