Search code examples
phpsilex

Silex 2 - Provider needs another service not yet registered


I have a service provider, that wants to call a method of another service from another provider, that is not yet registered. How can i solve this?

Let's say i have a service $app["two"] that has a doStuff() method. Then i have a service $app["one"]. During registration of $app["one"], it's service provider needs to call the $app["two"]->doStuff() method, but since the provider of $app["two"] is registered after $app["one"], that is impossible since silex doesnt know it yet.

The Provideder of $app["one"]:

class OneServiceProvider implements ServiceProviderInterface {

    public function register(Container $app) {

        $app['one'] = function () use ($app) {
            $app['two']->doStuff(); // <- Error since not yet registered!
            return new OneService();
        };
    }
}

The registration part of the main app:

$app->register(new OneServiceProvider());
$app->register(new TwoServiceProvider());

In Silex 1, i think there was this extend method, which could extend/change a service when it is registered. In silex 2, i couldnt find anything similar. Is there any solution to it or should i dispatch an event in $app["two"] and subscribe to it in $app["one"]? Or should i use the boot method to call $app["two"]?


Update

I just tried the $app->extend approach. Sadly it still threw an error calling member function doStuff() on null

class OneServiceProvider implements ServiceProviderInterface {

public function register(Container $app) {

    $app['one'] = function () use ($app) {
        $one = new OneService();
        $app->extend("two", function($two, $c){
            $two->doStuff();
        })
        return $one;
    };
}

}


Solution Since i can no longer reproduce the original issue in clean test code, i'll have to assume that the problem was unrelated. Silex 2 seems to take care of this problem, no matter how you access services during their registration. Tnx for your help anyways!


Solution

  • I think your problem is the lazy call. Don't use this :

    $app['one'] = function () use ($app) {
    

    but :

    $app['one'] = function (Container $app) {
    

    In the first one, the app don't have provider two.

    UPDATE

    It's working for me :

    TwoServiceProvider.php

    class TwoServiceProvider implements ServiceProviderInterface
    {
        public function register(Container $app)
        {
            $app['two'] = function() {
                return new Test();
            };
        }
    }
    

    OneServiceProvider.php

    class OneServiceProvider implements ServiceProviderInterface
    {
        public function register(Container $app)
        {
            $app['one'] = function(Container $app) {
                $app['two']->doStuff();
                return new Test2();
            };
        }
    }
    

    index.php

    $app->register(new OneServiceProvider());
    $app->register(new TwoServiceProvider());
    $app['one']->doStuff();