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

[FEATURE] Add Auto-Registration and Dependency Resolution to DI Container in Pancake #237

Open
4 tasks
guibranco opened this issue Oct 21, 2024 · 2 comments · May be fixed by #253
Open
4 tasks

[FEATURE] Add Auto-Registration and Dependency Resolution to DI Container in Pancake #237

guibranco opened this issue Oct 21, 2024 · 2 comments · May be fixed by #253
Labels
🧠 backlog Items that are in the backlog for future work ♻️ code quality Code quality-related tasks or issues 📝 documentation Tasks related to writing or updating documentation enhancement New feature or request gitauto GitAuto label to trigger the app in a issue. 🕔 high effort A task that can be completed in a few days 🧑‍💻 tech-debit Technical debt that needs to be addressed 🧪 tests Tasks related to testing 🛠 WIP Work in progress

Comments

@guibranco
Copy link
Owner

guibranco commented Oct 21, 2024

Description:
I would like to enhance the DI Container in the Pancake project to support auto-registration for services that are not explicitly registered in the container. This auto-registration feature should be enabled by default but configurable via a flag. Additionally, the container should be able to automatically resolve all dependencies, including constructor dependencies, for services that are auto-registered.

Related to #235

Below is an updated code example for the DIContainer class illustrating the requested functionality:

Updated DIContainer Example

<?php

namespace GuiBranco\Pancake;

class DIContainer
{
    private array $services = [];
    private array $sharedInstances = [];
    private bool $autoRegisterEnabled = true;

    public function __construct(bool $autoRegisterEnabled = true)
    {
        $this->autoRegisterEnabled = $autoRegisterEnabled;
    }

    public function register(string $name, callable $resolver, bool $shared = false)
    {
        $this->services[$name] = [
            'resolver' => $resolver,
            'shared' => $shared,
        ];
    }

    public function resolve(string $name)
    {
        if (isset($this->services[$name])) {
            if ($this->services[$name]['shared']) {
                if (!isset($this->sharedInstances[$name])) {
                    $this->sharedInstances[$name] = $this->services[$name]['resolver']($this);
                }
                return $this->sharedInstances[$name];
            }
            return $this->services[$name]['resolver']($this);
        }

        if ($this->autoRegisterEnabled) {
            return $this->autoRegister($name);
        }

        throw new \Exception("Service '{$name}' not registered.");
    }

    private function autoRegister(string $name)
    {
        if (!class_exists($name)) {
            throw new \Exception("Class '{$name}' does not exist.");
        }

        $reflectionClass = new \ReflectionClass($name);
        $constructor = $reflectionClass->getConstructor();

        if ($constructor === null) {
            return new $name(); // No constructor, no dependencies.
        }

        $parameters = $constructor->getParameters();
        $dependencies = [];

        foreach ($parameters as $parameter) {
            $parameterClass = $parameter->getType() ? $parameter->getType()->getName() : null;

            if ($parameterClass && class_exists($parameterClass)) {
                $dependencies[] = $this->resolve($parameterClass);
            } else {
                throw new \Exception("Cannot resolve parameter '{$parameter->getName()}' for class '{$name}'.");
            }
        }

        return $reflectionClass->newInstanceArgs($dependencies);
    }

    public function registerSingleton(string $name, callable $resolver)
    {
        $this->register($name, $resolver, true);
    }

    public function registerTransient(string $name, callable $resolver)
    {
        $this->register($name, $resolver, false);
    }

    public function setAutoRegisterEnabled(bool $enabled)
    {
        $this->autoRegisterEnabled = $enabled;
    }
}

New Features:

  1. Auto-Registration of Services:

    • If a service is not found in the registration array, the DI container will attempt to auto-register it by resolving its constructor dependencies.
    • This auto-registration feature is enabled by default, but can be controlled using the setAutoRegisterEnabled method.
  2. Dependency Resolution:

    • The DI container will automatically resolve constructor dependencies for both explicitly registered and auto-registered services.
    • It will recursively resolve dependencies for services that require other services as constructor arguments.

Example of Auto-Registration:

<?php

// Assume a service with dependencies
class ServiceA {
    public function __construct(ServiceB $serviceB) { }
}

class ServiceB {
    public function __construct(ServiceC $serviceC) { }
}

class ServiceC {
    public function __construct() { }
}

$container = new \GuiBranco\PocMvc\Src\Core\DIContainer();

// Automatically registers and resolves ServiceA, along with its dependencies (ServiceB, ServiceC)
$serviceA = $container->resolve(ServiceA::class);

Task Requirements:

  • Add auto-registration functionality to the DI Container with support for resolving dependencies via reflection.
  • Include a flag to enable/disable auto-registration (enabled by default).
  • Ensure that both registered and auto-registered services have their dependencies resolved recursively.

Additional Requirements:

  • Provide unit tests to verify:
    • Auto-registration of services when not explicitly registered.
    • Dependency resolution, including recursive dependencies.
    • Correct behavior when auto-registration is disabled.
  • Include integration tests to validate the new functionality in practical use cases.

Acceptance Criteria:

  • The DI container supports auto-registration and dependency resolution.
  • Services with complex dependencies can be automatically resolved.
  • Unit and integration tests are provided.
  • Documentation is updated with usage examples for both manual and auto-registration.
@guibranco guibranco added 📝 documentation Tasks related to writing or updating documentation enhancement New feature or request 🧠 backlog Items that are in the backlog for future work 🧪 tests Tasks related to testing ♻️ code quality Code quality-related tasks or issues 🧑‍💻 tech-debit Technical debt that needs to be addressed 🕔 high effort A task that can be completed in a few days labels Oct 21, 2024
Copy link
Contributor

gitauto-ai bot commented Oct 21, 2024

Click the checkbox below to generate a PR!

  • Generate PR

@guibranco, You have 5 requests left in this cycle which refreshes on 2024-11-21 10:07:38+00:00.
If you have any questions or concerns, please contact us at [email protected].

@gitauto-ai gitauto-ai bot added the gitauto GitAuto label to trigger the app in a issue. label Oct 25, 2024
Copy link
Contributor

gitauto-ai bot commented Oct 25, 2024

Hey, I'm a bit lost here! Not sure which file I should be fixing. Could you give me a bit more to go on? Maybe add some details to the issue or drop a comment with some extra hints? Thanks!

Have feedback or need help?
Feel free to email [email protected].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🧠 backlog Items that are in the backlog for future work ♻️ code quality Code quality-related tasks or issues 📝 documentation Tasks related to writing or updating documentation enhancement New feature or request gitauto GitAuto label to trigger the app in a issue. 🕔 high effort A task that can be completed in a few days 🧑‍💻 tech-debit Technical debt that needs to be addressed 🧪 tests Tasks related to testing 🛠 WIP Work in progress
Projects
None yet
1 participant