Skip to content
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

Factory Parameters #362

Closed
bradynpoulsen opened this issue Jan 4, 2016 · 6 comments
Closed

Factory Parameters #362

bradynpoulsen opened this issue Jan 4, 2016 · 6 comments
Labels
Milestone

Comments

@bradynpoulsen
Copy link
Contributor

@bradynpoulsen bradynpoulsen commented Jan 4, 2016

It would be really nice if I could define specific parameters in my factory.

Take the following example where I want to build an array of delegates for a handler

class SomeHandlerFactory
{
    public function create(SomeHandler $handler, array $delegates)
    {
        $handler->doSomethingCool();
        array_map([$handler, 'pushDelegate'], $delegates);
        return $handler;
    }
}

I would like to define the array of delegates to isolate accessing the container directly to my config.php

// config.php
return [
    'SomeHandler' => factory(['SomeHandlerFactory', 'create'])->param('delegates', get('handlerDelegates')),
    'handlerDelegates' => function (ContainerInterface $container) {
        $delegates = [];
        if (Config::get('someSetting')) {
            array_push($delegates, $container->get('DelegateA'));
        }
        if (Config::get('awesomeMode')) {
            array_push($delegates, $container->get('ImpeachTheOffice'));
        }
        return $delegates;
    }
];
@mnapoli mnapoli added the enhancement label Jan 5, 2016
@mnapoli
Copy link
Member

@mnapoli mnapoli commented Jan 5, 2016

👍 thanks for the suggestion

@klinki
Copy link

@klinki klinki commented Feb 8, 2016

👍 This would be great feature. I need something similar. But I also need information about currently resolved class (at least name).

I have cache factory which accepts string as a key and several classes using cache.

class CacheFactory 
{
   protected $existingCaches = [];

   public function create($name)
   {
      if (!array_key_exists($name, $this->existingCaches)) {
           $this->existingCaches[$name] = new Cache();
      }

      return $this->existingCaches[$name];
   }
}
class CacheClientA 
{
    public function __construct(Cache $cache)
    {
           ......
    }
}
class CacheClientB
{
    public function __construct(Cache $cache)
    {
           ......
    }
}

It would be really great, if DI could call create method on CacheFactory and pass CacheClient class name as parameter.

@mnapoli
Copy link
Member

@mnapoli mnapoli commented Feb 8, 2016

@klinki it's possible to retrieve the requested entry name, have a look here: http://php-di.org/doc/php-definitions.html#retrieving-the-name-of-the-requested-entry

@klinki
Copy link

@klinki klinki commented Feb 8, 2016

Thanks :) I missed that. It works quite well with wildcards.

Is it possible to mix it with DI\object()->constructorParameter?

Right now I have this code:

 'CacheClients\*' => function(Container $container, RequestedEntry $entry) {
     $cacheFactory = $container->get(Factory::class);
     $className= $entry->getName();
     $cache = $cacheFactory->getCache($className);
     return new $className(
           $container->get(Connection::class),
            $cache,
            $container->get(LoggerInterface::class)
     ); 
}

It is fine now, when I have just a few dependencies, but for classes with lots of dependencies, this would get quite long.

It would be really awesome, if I could use constructorParameter. Maybe something like this:

'CacheClients\*' => object()->constructorParameter('cache', function(Container $container, RequestedEntry $entry) {
    $cacheFactory = $container->get(Factory::class);
    $className= $entry->getName();
    return $cacheFactory->getCache($className);
}
@mnapoli
Copy link
Member

@mnapoli mnapoli commented Feb 8, 2016

@klinki It's not possible right now :) I'm afraid it might make the configuration quite complex though

@predakanga
Copy link
Contributor

@predakanga predakanga commented Mar 12, 2016

Just wanted to throw a +1 behind this, with a use-case.

I'm using Doctrine DBAL as a DB layer, was hoping to be able to use their factory class and a lazy proxy, as follows:

use DI\factory;
use DI\get;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\DriverManager;

return [
    Connection::class => factory([DriverManager::class, 'getConnection')->factoryParameter('params', [
        'host' => get('db.host'),
        'port' => get('db.port'),
        'dbname' => get('db.name'),
        'user' => get('db.user'),
        'password' => get('db.pass)
    ])->lazy();
];

In reality, the closest I can come is by using a closure, like so:

use DI\factory;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\DriverManager;
use Interop\Container\ContainerInterface;

return [
    Connection::class => function(ContainerInterface $c) {
        return DriverManager::getConnection([
            'host' => $c->get('db.host'),
            'port' => $c->get('db.port'),
            'dbname' => $c->get('db.name'),
            'user' => $c->get('db.user'),
            'password' => $c->get('db.pass')
        ]);
    }
];

And even there there's no way of applying the lazy tag; that would require writing a wrapper class.

@mnapoli mnapoli mentioned this issue Mar 15, 2016
@mnapoli mnapoli changed the title Feature Request: Factory Parameters Factory Parameters May 15, 2016
predakanga added a commit to predakanga/PHP-DI that referenced this issue Jul 9, 2016
@mnapoli mnapoli closed this in 6a8483d Jul 14, 2016
@mnapoli mnapoli added this to the 5.4 milestone Aug 23, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.