radarphp / Radar.Adr

The Action-Domain-Responder core for Radar.
MIT License
55 stars 7 forks source link

How to call a Domain object from another Domain object? #35

Closed cxj closed 5 years ago

cxj commented 7 years ago

Is there a simple, clean way for the MyDomain I specify in something like

$adr->get('path', '/path', App\MyDomain::class);

to call other domain objects? I see that Radar\Adr\Resolver has been injected with $di->getInjectionFactory(), but I don't see an easy way for my code to duplicate Resolver's technique for generating the callable I need.

Help?

jakejohns commented 7 years ago

Can you elaborate with more concrete specifics? You could inject the resolver if you really needed to, but then you're probably stating to creep towards service locater territory.

Maybe I'm missing something, but why wouldn't this MyDomain just have whatever else it needs to call injected into the constructor?

cxj commented 7 years ago

Hopefully this will help. All my objects are wired up for DI using Aura\Di. When Radar calls them, it does the necessary magic to make sure they get created with dependencies properly injected. But I'm struggling with doing the resolution of my class name into a callable (which is what Radar and Arbiter do internally). In the following example, Foo is both called from a Radar action directly, and I want to re-use its code by calling it form within another domain, Bar.

/**
* @var \Radar\Adr\Adr $adr
*/
$adr->get('foo', '/foo', Domain\Foo::class);
$adr->get('bar', '/bar', Domain\Bar::class);

class Foo extends App {
    protected function exec(array $input) {
        $request = new Request\DatasourceFoo($input);
        $response = $this->gateway->fetchResponse($request);

        $payload = new Aura\Payload\Payload();
        $payload->addOutput($response->getData);
        return $payload;
    }
}

class Bar extends App {
    protected function exec(array $input) {
        // Somehow call Foo here.
        $foo = new Foo(???);
        $payload = $foo();      // __invoke()
        // Reformat data and reuse in different form.
        $data = $payload->getData();
        // ...
        return $payload;
    }
}
jakejohns commented 7 years ago

With all the meta-syntactic names, its hard to tell for sure, but there might be something else wrong here. If your domains are themselves consuming domain payloads, I question if things are considered correctly.

That being said why not just:


class Bar extends App
{
    protected $foo;

    // Foo is just a dependency of Bar
    public function __construct(Foo $foo)
    {
        $this->foo = $foo;
    }

    public funciton __invoke($input)
    {
        $fooLoad = $this->foo($input);
        // ...
    }
}

Or really, possibly just:

class Bar extends Foo
{
    // ... now bar can do everything foo can do, no?
}

But really, can't $gateway just do all the things u want it to do in both contexts?

If you REALLY needed too (and I think its probably a bad idea), you could:

class Bar
{
    protected $resolver;

    public function __construct(callable $resolver)
    {
        $this->resolver = $resolver;
    }

    public function __invoke()
    {
        $resolve = $this->resolver;
        $foo = $resolve(Foo::class);
    }
}

You could inject the radar resolver, or the aura/di resolution helper thats in the newer version of 3.x, but I'm not sure thats really what you want to do...

cxj commented 7 years ago

I very much appreciate all the feedback, and also the time you've taken to understand my problem. I suspect I have not been particularly clear on what I'm trying to accomplish. That said, what you've written above will take me a while to digest. As you suggest, I may be going about it all wrong by having my Bar domain consume the output of my Foo domain. And really all I'm trying to do is be DRY and avoid duplicate code doing the same work. Thanks much. I'll come back when I've got something intelligent to say. ;-)

cxj commented 5 years ago

I think I have figured out that I was structuring things wrongly. If Foo and Bar are sharing some of the same underlying code, that shared code should be a service called by both, rather than Bar calling Foo (mostly because Foo was written first). So I needed to refactor, which I've done, and it works. It's also a lot easier to understand.