Git viewing holonet/common / bf853db1b818caac37856cf8b80e1e429fd13982 / src/di/Container.php


Filter

      <?php
/**
 * This file is part of the holonet common library
 * (c) Matthias Lantsch.
 *
 * Class file for the Dependency Injection Container class
 *
 * @license http://opensource.org/licenses/gpl-license.php  GNU Public License
 * @author  Matthias Lantsch <[email protected]>
 */

namespace holonet\common\di;

use TypeError;
use Psr\Container\ContainerInterface;

/**
 * Dependency Injection container conforming with PSR-11.
 */
class Container implements ContainerInterface {
	/**
	 * @var string DI_PREFIX Prefix value for the injected class properties
	 */
	public const DI_PREFIX = 'di_';

	/**
	 * @var array A key value storage with dependency objects
	 */
	private $dependencies = array();

	/**
	 * {@inheritdoc}
	 */
	public function get($id) {
		if (!$this->has($id)) {
			throw new DependencyNotFoundException("Dependency '{$id}' does not exist on Dependency Container");
		}

		return $this->dependencies[$id];
	}

	/**
	 * {@inheritdoc}
	 */
	public function has($id) {
		return isset($this->dependencies[$id]);
	}

	/**
	 * Method used to inject dependencies into an object, here called "the user of the dependencies".
	 * @param object $dependencyUser The object to be injected
	 * @param bool $forceInjection Whether to throw an exception if a dependency cannot be found
	 */
	public function inject(object $dependencyUser, bool $forceInjection = true): void {
		foreach ($dependencyUser as $propertyName => $propertyValue) {
			if (mb_strpos($propertyName, static::DI_PREFIX) === 0) {
				$depKey = str_replace(static::DI_PREFIX, '', $propertyName);
				if (!$this->has($depKey) && $forceInjection) {
					throw new DependencyNotFoundException("Dependency '{$depKey}' does not exist on Dependency Container");
				}
				$dependencyUser->{$propertyName} = $this->get($depKey);
			}
		}
	}

	/**
	 * Method used to set a dependency in this class.
	 * If the given value is an object, it will get injected and saved under the key
	 * If the given value is a string a class name is assumed and a new object will be created and automatically get injected.
	 * @param string $id The key to save the dependency under
	 * @param object|string $value The dependency to save
	 * @param array ...$constructorArgs Arguments for the class instantiation
	 */
	public function set(string $id, $value, ...$constructorArgs): void {
		if (is_string($value) && class_exists($value)) {
			try {
				$value = new $value(...$constructorArgs);
			} catch (TypeError $e) {
				throw new DependencyInjectionException(
					"Cannot create dependency '{$id}' on Dependency Container: '{$e->getMessage()}'",
					$e->getCode(), $e
				);
			}
		}

		if (!is_object($value)) {
			throw new DependencyInjectionException(
				"Cannot set dependency '{$id}' on Dependency Container, value must be object or class string"
			);
		}

		$this->inject($value);
		$this->dependencies[$id] = $value;
	}
}