Giter Site home page Giter Site logo

container's People

Contributors

admad avatar arai-ta avatar art4 avatar azjezz avatar bwg avatar chrisguitarguy avatar claudiunicolaa avatar craig-mcmahon avatar dannyvdsluijs avatar elazar avatar gamringer avatar glensc avatar grahamcampbell avatar greg-1-anderson avatar hannesvdvreken avatar jamesdb avatar jenssegers avatar jleeothon avatar localheinz avatar makstech avatar nunomaduro avatar odan avatar pascal-hofmann avatar philipobenito avatar philsturgeon avatar pine3ree avatar sagikazarmark avatar subhansh avatar szepeviktor avatar tangrufus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

container's Issues

Combine Closure and Callable definitions

Similarities between CallableDefinition and ClosureDefinition mean they can be combined and the functionality surrounding Container::invokable and Container::call can be proxied through. This also has the benefit of allowing any callable to be used as as a factory for building objects.

Adding an instance of a class which has an __invoke method

I'm not sure if this is expected behavior or not, but here goes:

When you add an instance of a class which has an __invoke method, the DefinitionFactory sees this as a callable, so it gets added as a CallableDefinition. As a consequence of this, when you try to get the $concrete it does not return the instance, but whatever the __invoke method returns.

Here's an example to make it a bit clearer

I think this might be a bug, because changing the innards of a class should probably not change what the container returns. If my thinking is correct, the fix would probably be handling objects which are not instances of Callable like any other undefineable item and just add them as an arbitrary value/instance (= like here.

I'm more than willing to PR this, but I'd rather make sure this is indeed a bug and not by design, because I can imagine being able to use __invoke has its uses too.

PSR-11 (ContainerInterface)

Hi, the PSR-11 (ContainerInterface) has been accepted. bit.ly/2lGHGz8

Currently this package (thephpleague/container) provides the "container-interop/container-interop-implementation" v.1.1. So it should be "easy" to migrate to v.1.2 (PSR-11) right?

Starting Feb. 13th 2017, container-interop is officially deprecated in favor of PSR-11. Container-interop has been the test-bed of PSR-11. From v1.2, container-interop directly extends PSR-11 interfaces. Therefore, all containers implementing container-interop are now de-facto compatible with PSR-11.

When are you planing to "update" from "container-interop/container-interop" v.1.1 to v1.2 (PSR-11)?

Rewrite public API

  • Separation of Concerns
  • Split input and output
  • Pull all reflection in to one object
  • Group specific functionality
  • Command line tools to create immutable container for production
  • Improve service provider functionality

Container's singleton method not in documentation.

I think you have a fantastic project here. It is lightweight and has everything that is needed for an IoC container. One problem I had when trying to learn the container was in how to add singletons to the container. The documentation has no reference to the container's singleton method. I feel as though it should be. I will gladly write it myself and submit a pull request if there are no objections to adding this.

How to override with using two Service Providers?

Hello, I use [https://github.com/jenssegers/lean] for integrate with League\Container and Slim. I wanted to override foundHandler and request without edit SlimServiceProvider class. If I use the same name, there is no effect. How to override named items in $provides array in SlimServiceProvider .

Impossible to override shared service if already resolved

I'm not sure if this is a bug or intended behavior so bear with me. If I share a value in the container, I am properly able to overwrite it:

$container = new League\Container\Container();

$container->share('foo', 'bar');
dump($container->get('foo')); // bar

$container->share('foo', 'baz');
dump($container->get('foo')); // baz

If however I share a factory, I can't overwrite it:

$container = new League\Container\Container();

$container->share('foo', function() {
    return 'bar';
});
dump($container->get('foo'));// bar

$container->share('foo', function() {
    return 'baz';
});
dump($container->get('foo')); // bar

Reason seems to be the container looks in $this->shared the second time even though the definition has changed, and thus it returns the resolved value. Shouldn't the resolved value be cleared when the definition changes?

Autowiring issue

I'm having some issues with the ReflectionContainer and autowiring. I tried digging into the code to do a PR, but I could not really figure out the problem yet.

In my example, I share a specific instance of a class first:

$container = new League\Container\Container;

$container->delegate(
    new League\Container\ReflectionContainer
);

$container->share('App\Client', function()
{
    return new App\Client('test', 'test');
});

And I have another class called App\SDK which requires a App\Client instance from the constructor. Here comes the bad part. When I try to create an instance of App\SDK using reflection, I'm getting a lot of errors:

$container->get('App\SDK');

PHP Fatal error:  Uncaught exception 'League\Container\Exception\NotFoundException' with message 'Unable to resolve a value for parameter (username) in the function/method (__construct)' in .../vendor/league/container/src/Argument/ArgumentResolverTrait.php:66

It seems like it tries to create the App\Client even though I have already bound an instance of it to the container. While digging into the code, I have noticed that $this->getContainer() returns NULL in the ArgumentResolverTrait. Shouldn't this contain the original container instance?

Getting the key value using ServiceProviders

So I may have overlooked something but I can't figure this out.

I am creating a bot that has a main object $this->bot and I want to add all the modules/services to that object.

So I setup the container etc. and I created a ServiceProvider for my module called "helloworld".

class ServiceProvider extends AbstractServiceProvider
{
    protected $provides = [
        'helloworld'
    ];

    public function register()
    {
        $this->getContainer()->add('helloworld', 'Bot\HelloWorld\HelloCommands');
    }
}

I then run the __construct of the main Bot class to register and load every single service I have:

class Bot {

    /**
     * Construct the bot and read the configurations.
     */
    public function __construct()
    {
        // Create the main DependencyInjection
        $bot = new Container;

        // Read the config into the main bot object
        $this->bot->config = $this->config();

        // Add services to the container from the config
        foreach ($this->bot->config['services'] as $service) {
            $bot->addServiceProvider($service);
        }

        $this->bot = $bot;
    }

        public function config()
    {
        return [
            "services" => [
                "Bot\HelloWorld\ServiceProvider"
            ],
        ];
    }
}

This is where I get stuck. How do I access the key "helloworld" when I have registered the service as "Bot\HelloWorld\ServiceProvider" so I can create this object:

$this->bot->helloworld
# So I can use the commands in HelloCommands class:
$this->bot->helloworld->sayHello();

Basically automate the following without knowing the namespace/key:

$this->bot->helloworld = $bot->get('helloworld');

Thanks.

Can't reliably store values (parameters) in container

If you try to store a string in the container and the string happens to be a valid classname then it will be converted to a service. For example

$database_host = 'db'; // lets assume there is a top level class named db
$container->add('database_host', $database_host);
var_dump($container->get('database_host')); // this is an instance of db and not the string we provided

I poked around in the code and there doesnt seem to be a way to change this behavior. It also seems a little implicit that you cant store a scalar/array value in the container except by using the ->add method which has this guessing behavior.

Is this container not meant to allow storing of simple values in addition to instances or am I missing something?

Aliased classes's constructor arguments not injected?

Take the following code:

class Foo {}

class Bar {
    public function __construct(Foo $foo) {}
}

$container = new Container();
$container->add('some.alias', 'Bar');

dump($container->get('Bar')); // Will work
dump($container->get('some.alias')); // Argument 1 passed to Bar::__construct() must be an instance of Foo, none given

Is there no way to have aliased services be auto-resolved, without having to specify all their constructor arguments manually like this:

$container->add('some.alias', 'Bar')->withArgument('Foo');

Leading backslash in class name

Should I use a leading backslash in class name when register new class:
$container->add('\SomeNS\ClassName');
instead of:
$container->add('SomeNS\ClassName');
What's difference?

isRegistered behavior in Container

It would appear that \League\Container\Container::isRegistered only checks the items array so for \League\Container\Definition/ClassDefinition.php::invokeMethods line 81, where you run the code

foreach ($method['arguments'] as $arg) {
  $args[] = ($this->container->isRegistered($arg)) ? $this->container->get($arg) : $arg;
}

The problem is if you try to inject a singleton using withMethodCall then it returns false however $this->container->get($arg) would actually return the correct singleton.

My use case is as follows:

$container
  ->add('command.tool', 'Namespace\Command\Tool')
  ->withMethodCall('setContainer', ['League\Container\Container']);

( Note in this case the class Namespace\Command\Tool implements the trait \League\Container\ContainerAwareTrait )

And since the container is a singleton it is not resolved.

Is this intended behaviour? ( If not i can throw up a pull request to either change the behaviour of isRegistered or change this if statement to run OR $this->container->isSingleton($arg) )

Using an alias does not properly look into the Service Providers

The commented line throws an error: Argument 1 passed to App\Users\UserMapper::__construct() must be an instance of Spot\Locator, none given. And the second line works properly, but defeats the purpose of lazy loading.

// $container->add('App\Authentication\UserMapperInterface', 'App\Users\UserMapper');
$container->add('App\Authentication\UserMapperInterface', $container->get('App\Users\UserMapper'));

The problem seems to be with Spot\Locator being registered in a service provider. Using the commented line, the container does not look into the providers to find the service, like it does when using the get method

Can't use extend with factory closures

It would be awesome to be able to use withMethodCall with CallableDefinition or at least have a method that would accept any callable and put the container value as the first argument. I need to be able to extend definitions from one provider to another:

//First provider

public function register() 
{
    $this->getContainer()->add('SomeClass', function() {return new SomeClass;});
}

//Second provider

public function boot()
{
    $this->getContainer()->extend('SomeClass')->withCallback(function($classObj, $otherArg) {
        $classObj->add($otherArg);
        return $classObj;
    }, ['otherArgFromContainer]);
}

What are your thoughts on this? Could it be added fast as a non breakable new feature? I can do a pull request if you want.

Construction via a named constructor

I use named constructors (static methods which return an instance of the class) fairly often. I'd really like to be able to do this with container.

It is currently possible using call and invokable but it has a different meaning semantically. And also using factory closures, but these are not possible through the config array.

I'm happy to create a PR for this but just wanted to see whether it's something which might be accepted before starting work on it.

So, what I propose is the following:

Given:

<?php

final class Foo
{
    public static function fromString($string)
    {
        return new self(/* ... */);
    }

    // ...
}

I'd like to be able to use container like so:

$container->add('Foo', ['Foo', 'fromString')->withArgument('some_value');
$foo = $container->get('Foo');

Also, double colon notation may be worth considering but has a danger of a BC break of anyone is using double colons in their names:

$container->add('Foo', 'Foo::fromString')->withArgument('some_value');
$foo = $container->get('Foo');

Finally, I'd like to see it so this is possible via the config array:

$config = [
    'Foo' = [
        'class' => 'Foo',  // 'Foo::fromString' could be possible also 
        'constructor' => 'fromString',
        'arguments' => [ 'some_value' ]
    ]
];

So thoughts? If I'd created a PR for this would it be considered?

Inflector Factory Closures

Hi,

It would be great to allow a way to have the inflector use a factory closure to create classes that implement an interface or extend a base class x.

For instance:

use My\ClassInterface;

$container->inflector(ClassInterface::class, function ($container, $concrete) {
    return ClassFactory::create($concrete);
});

What is your thought on that?

Allow reflected classes to have passed arguments

When the definition of a reflected class is created, it is not possible to pass arguments to it. At least currently the definition returned from the reflect method is not called with the arguments passed to the get method. Why is that?

Allow knowledge of variadic callables

Considering the new Container::call functionality, I feel there should be a way to pass concrete runtime arguments to the callable separately to the dependencies that are defined.

It doesn't necessarily need to be >5.6 only, the callable would simply need to define the correct amount of arguments.

< PHP 5.6

$container->invokable('some_callable', function (SomeDependency $somedependency, $variadic1, $variadic2) {
    // ...
})->withArgument('SomeDependency');

$container->call('some_callable', ['variadic1 value', 'variadic2 value']);

>= PHP 5.6

$container->invokable('some_callable', function (SomeDependency $somedependency, ...$params) {
    // ...
})->withArgument('SomeDependency');

$container->call('some_callable', ['variadic1 value', 'variadic2 value']);

The main motivation behind this is to be able to use Container::call within a strategy for League\Route, allowing for dependencies to be defined per controller action but still pass in values from wildcard segments of the URI.

Service providers are instantiated several times

Currently every service provider, which is added to the container is instantiated by the container every time it checks a service provider. Furthermore, setContainer is called every time as well which is unnecessary if the service provider is already instantiated.

Duplicate names overriding eachother

I created two ServiceProviders with their own namespace.

But if I register the same key (hellocommands) in both (notice HelloWorld and HelloWorld2).

This code exists in their respective ServiceProvider.php class, I just type both here to illustrate.

$this->getContainer()->add('hellocommands', 'Bot\HelloWorld\HelloCommands');
$this->getContainer()->add('hellocommands', 'Bot\HelloWorld2\HelloCommands');

Only the latter exists in the container.

When I do this:

$this->getContainer()->add('1_hellocommands', 'Bot\HelloWorld\HelloCommands');
$this->getContainer()->add('2_hellocommands', 'Bot\HelloWorld2\HelloCommands');

Both shows up.

Is this normal?

How would I go about forcing modules of my application to have unique key names to avoid this since it seems it does not use namespace to separate them?

Multiple calls to the same method

Currently you can only call a method once since method names are stored as keys of an associative array. Would be awesome if we could call a method multiple times. Use case: adding "extensions" to an object.

[rfc] Feature to automatically inject dependency when interface is implemented

For example, when an object implements ContainerAwareInterface the container could be aware that when this is resolved, it should call a defined setter (setContainer) to inject something.

$container = new League\Container\Container();

$container->context(League\Container\ContainerAwareInterface::class)
    ->withMethodCall('setContainer', [$container]);

Or something. The context method is just a temporary name. There must be a better suited name.

When an object which has this interface implemented, the setContainer method will be called automatically on the resolved object, right before the end of $container->get(Vendor\MyClass::class).

Allow runtime constructor parameters for Container::get via the $args param

I couldn't find a definition about the param $args to Container::get() in the docs.
I am using Auto Dependency Resolution.
The param seems to be ignored after line 202 in src/Container.php, which handles the auto-resolution.

What i would expect:
Using the $args param, it should be possible to inject further parameters into the constructor of the class.
Possibly even overriding defined parameters..

I'd be happy to do a pull-request, but i want to see whether this needs to be discussed first.

Autowiring broken when loading class via shared interface

I have a KernelInterface class which is implemented by various different user definable Kernel classes with the default being a DefaultKernel class; this is handled by the following code:

if (file_exists($kernelPath)){
    include $kernelPath;
    $container->share(KernelInterface::class, $configuration->get('kernel', DefaultKernel::class));
}else{
    $container->share(KernelInterface::class, DefaultKernel::class);
}

/** @var KernelInterface $kernel */
$kernel = $container->get(KernelInterface::class);
$kernel->boot();

The KernelInterface is as follows:

interface KernelInterface
{
    public function boot();
}

The DefaultKernel is as follows:

class DefaultKernel implements KernelInterface
{
    /**
     * @var Project
     */
    private $project;

    /**
     * DefaultKernel constructor.
     * @param Project $project
     */
    public function __construct(Project $project)
    {
        $this->project= $project;
    }

    public function boot()
    {
        // ...
    }
}

If the implementation of KernelInterface doesn't have a __construct it works fine and the kernel's boot method will be executed; however with the __construct I get the following error message:

Catchable fatal error: Argument 1 passed to App\Modules\Kernel\DefaultKernel::__construct() must be an instance of App\Project, none given

The only way I can get Project to be autowired is if I use the class name directly $kernel = $container->get(DefaultKernel::class); instead of via the interface.

I have auto-wiring enabled via the use of the League\Container\ReflectionContainer delegate.

Is this a bug or am I doing something wrong?

Method call be part of all definitions

IMO Callable and Closure also return an object. Why can't addMethodCall(s) be bart of the whole interface? In some cases it can also be useful (for example when extending a definition).

Add string escaping

In some cases an argument can be a class name (eg. a doctrine entity name). In this case I don't want the container to instantiate the class, but pass it as is. To achieve this, there could be a string escaping/expression function/wrapper object (which then gets removed during argument resolution).

Can't seem to add values from a service provider

Hi, not quite sure if it's just me being stupid or this just not being possible:

use League\Container\Container;
use League\Container\ServiceProvider;


class MyServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->getContainer()['key'] = 'value';
    }
}

$container = new Container();
$container->add(new MyServiceProvider);
var_dump($container->get('key'));

It throws:

Fatal error: Uncaught exception 'League\Container\Exception\ReflectionException' with message 'Unable to reflect on the class [key], does the class exist and is it properly autoloaded?' in /Volumes/Data HD/Dropbox/Projects/snap/vendor/league/container/src/Container.php on line 401

I've used Pimple in the past and this seems to work just fine ๐Ÿ˜•

Have InflectorAggregate::inflect() also look at traits?

When the InflectorAggregate inflects on an object, it doesn't look at traits, only interfaces.

I was wondering if it would be worth the effort of adding support for traits?

Arguments against such a thing could be that traits shouldn't be used for inflection or that adding extra code (and thus extra complexity) isn't desired.

So before opening a PR to that effect, I thought it might be wise to post this question first.

Suggestion: Improve callable functionality and allow runtime arguments on call

I see you are working on version 2, which probably would have option described in title properly implemented, but since it will probably take a while to release I would like to propose quick hotfix for version 1 to also has this option implemented.

Registering factory in the container could be done as registering some FactoryProxy object that would store given callable in one of its fields. During creation of object, this callable would be taken from this wrapper and call() would execute it as normal function. Thanks to that you can have Factories with param resolution. Easy, powerful, quite dirty but good enough for version 1.

What do you think?

Question: where to define inflectors?

I had an issue where I had put

$this->container->inflector(ContainerAwareInterface::class)
            ->inflect('setContainer', [ContainerInterface::class]);

inside the register method of a ServiceProvider. The register method wasn't called because the resolved object wasn't referenced in the container as a ContainerAwareInterface implementation object.

Add Container::withRawArgument()

Expected behaviour:

$container->share(Client::class)
            ->withRawArgument([
                'base_uri' => $config->get('base_uri'),
                'handler'  => $container->get(HandlerStack::class),
            ]);

Current behaviour:

$container->share(Client::class)
            ->withArgument(new RawArgument([
                'base_uri' => $config->get('base_uri'),
                'handler'  => $container->get(HandlerStack::class),
            ]));

Would this be acceptable? I can make the PR, it just saves having to import a RawArgument class ๐Ÿ˜„

Shared entry isn't shared when getting it from delegated container

Just set up a project with autowiring when I noticed that when the container has to fetch it from a delegate for autowiring it isn't stored in the container as share entry even though I marked it as shared in the first place. Is this intended behavior?

Current behavior:

$container = new Container();
$container->delegate(new ReflectionContainer());
$container->share('Acme\Foo', new Acme\Foo());

var_dump(
    $container->get('Acme\Foo') === $container->get('Acme\Foo')
); // false, two different instances are returned

Expected behavior:

$container = new Container();
$container->delegate(new ReflectionContainer());
$container->share('Acme\Foo', new Acme\Foo());

var_dump(
    $container->get('Acme\Foo') === $container->get('Acme\Foo')
); // true, both return the same instance

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.