# How to access ServiceLocatorInterface features if we "only" get a ContainerInterface passed into FactoryInterface

**URL:** <https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603>\
**Category:** Components & MVC\
**Tags:** laminas-servicemanager\
**Created:** [November 19, 2021, 3:51pm UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603 "2021-11-19T15:51:22Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![steffendietz](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/steffendietz/32/1197_2.png) [@steffendietz](https://discourse.laminas.dev/u/steffendietz)\
**Post date:** [November 19, 2021, 3:51pm UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/1 "2021-11-19T15:51:22Z")

</div>

Hi Laminas community,

I currently have the use-case that I want to pass options into a factory from within another factory.  
I thought I would use the `build` method of the `ServiceManager`.

But now I’m facing the problem, that the `ContainerInterface` passed into my factories does not expose that method.  
Well technically the `$container` object I’m receiving exposes it, because it’s the `ServiceManager`. But the contract does not guarantee it.

What am I missing?

---

<div class="post-metadata">

**Author:** ![guidofaecke](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/guidofaecke/32/427_2.png) [@guidofaecke](https://discourse.laminas.dev/u/guidofaecke)\
**Post date:** [November 19, 2021, 6:23pm UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/2 "2021-11-19T18:23:10Z")

</div>

Could you be a bit more specific, maybe a code snippet, so we can see what the idea behind it might be?

---

<div class="post-metadata">

**Author:** ![steffendietz](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/steffendietz/32/1197_2.png) [@steffendietz](https://discourse.laminas.dev/u/steffendietz)\
**Post date:** [November 20, 2021, 9:18am UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/3 "2021-11-20T09:18:02Z")

</div>

Okay. My use-case is pretty much analogue to the one [described in the documentation](https://docs.laminas.dev/laminas-servicemanager/configuring-the-service-manager/#passing-config-to-a-factorydelegator)

The `__invoke` method signature of the current `FactoryInterface` looks like this:

```php
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null);

```

I want to pass in the `$options` from another factory using the `build()` method of the `ServiceManager`.

So I would basically have two factories:

```php
// ValidatorFactory
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null) {
    return new Validator($options['length'] ?? 0);
}

```

```php
// FormFactory
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null) {
    $validator1 = $container->build(Validator::class, ['length' => 12]); // ContainerInterface only exposes get and has
    $validator2 = $container->build(Validator::class, ['length' => 20]); // ContainerInterface only exposes get and has
    $form = new Form();
    $form->addValidators([$validator1, $validator2]);
    return $form;
}

```

So essentially I want to use this `build()` method to pass `$options` to the factory like described in the documentation, but I seem to struggle with how this is supposed to work, since the contract of the factory does not guarantee, that I get a `$container` which implements the `ServiceLocatorInterface` I would need.

Thanks for listening. 🙂

---

<div class="post-metadata">

**Author:** ![steffendietz](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/steffendietz/32/1197_2.png) [@steffendietz](https://discourse.laminas.dev/u/steffendietz)\
**Post date:** [November 22, 2021, 8:02am UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/4 "2021-11-22T08:02:39Z")

</div>

Was my added example sufficiently specific? (@guidofaecke)

Maybe some project maintainer/designer who could shed some light here? 😅

---

<div class="post-metadata">

**Author:** ![makxk](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/makxk/32/1266_2.png) [@makxk](https://discourse.laminas.dev/u/makxk)\
**Post date:** [November 23, 2021, 8:23am UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/5 "2021-11-23T08:23:01Z")

</div>

Hi!  
this is how I do it:

```auto
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $serviceManager = $container->get(ServiceManager::class);
        return new FileSystem($serviceManager->build(Validator::class, $options));
    }

```

You were right that the $container does not expose `build`, the ServiceManager does.  
This leads to me getting the ServiceManager first, and then calling the `build` on it instead of the ContainerInterface.

Hope this helps 🙂

---

<div class="post-metadata">

**Author:** ![steffendietz](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/steffendietz/32/1197_2.png) [@steffendietz](https://discourse.laminas.dev/u/steffendietz)\
**Post date:** [November 23, 2021, 9:59am UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/6 "2021-11-23T09:59:25Z")

</div>

Hi @makxk,

thank you for your input. In fact I’m doing something similar currently:

```php
public function __invoke(ContainerInterface $container, $requestedName, array $options = null) {
    // THIS HERE
    assert($container instanceof ServiceLocatorInterface, 'Only usable in ServiceLocator context.');

    $validator1 = $container->build(Validator::class, ['length' => 12]);
    // ...
}

```

While I find it reasonable that the `ServiceManager` implements the `PSR-11` container interface, I find it strange, that the `FactoryInterface` bundled with the `ServiceManager` doesn’t expose all of its features or rather doesn’t make it intuitive as to what type of container you’ll most likely get in a Laminas environment.

I thought there is something that I missed.

I feel like the default `FactoryInterface` shipped with the component and also mentioned in the documentation should look more like this:

```php
public function __invoke(ServiceLocatorInterface $container, $requestedName, array $options = null);

```

and maybe, for convenience reasons, should also ship with a `Psr11FactoryInterface` which then would just be:

```php
public function __invoke(ContainerInterface $container, $requestedName, array $options = null);

```

I think I will leave this topic open for a while and hope that some core developer might also chime in. 😅

Thank you so much.

---

<div class="post-metadata">

**Author:** ![makxk](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/makxk/32/1266_2.png) [@makxk](https://discourse.laminas.dev/u/makxk)\
**Post date:** [November 24, 2021, 7:50am UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/7 "2021-11-24T07:50:46Z")

</div>

I feel like I should emphasize that there’s no `build` method in `ContainerInterface` _but in `ServiceManager`_, which implements `ServiceLocatorInterface`. How about you use the `ContainerInterface` to get a `ServiceManager` and call its `build` method like I did?  
All of those interfaces and classes are within the laminas-namespace, therefore are available to you too.

---

<div class="post-metadata">

**Author:** ![steffendietz](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/steffendietz/32/1197_2.png) [@steffendietz](https://discourse.laminas.dev/u/steffendietz)\
**Post date:** [November 24, 2021, 8:25am UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/8 "2021-11-24T08:25:05Z")

</div>

I’m very aware of that. It’s the sole reason I asked about the underlying concepts, and what the idiomatic way, a laminas user is “supposed to” use the features of the `ServiceManager` is.

Are we “supposed to” fetch it explicitly in every factory we would need the `build` method?  
Or are we “supposed to” assert, that the `$container` passed into the factory posseses the feature we are actually interested in?

The `ServiceManager` is currently the concept used in the Laminas world to obtain services. I’m wondering why it is not passed into my Laminas factories, so that I can use all of its features without prior having to fetch it.  
Maybe for context: In ZF2 the `ServiceLocatorInterface` was in fact passed into the factory. I’m worried that there was an oversight during the refactor.

Long story short: I’m interested in the idiomatic way. The way the _designer_ intended this to be used.

---

<div class="post-metadata">

**Author:** ![makxk](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/makxk/32/1266_2.png) [@makxk](https://discourse.laminas.dev/u/makxk)\
**Post date:** [November 24, 2021, 8:40am UTC](https://discourse.laminas.dev/t/how-to-access-servicelocatorinterface-features-if-we-only-get-a-containerinterface-passed-into-factoryinterface/2603/9 "2021-11-24T08:40:36Z")

</div>

I see, thanks for clarifying.  
In this case, maybe @froschdesign is be able to answer?
