2020use Psr \Container \ContainerInterface ;
2121
2222/**
23- * Class ConfigContainer.
23+ * Class ConfigContainer
2424 *
2525 * Provides a PSR-11 compatible container interface for accessing configuration values.
26- * This container MAY be used in dependency injection systems where configuration keys
27- * should be resolvable via standard container access.
26+ *
27+ * This container implementation SHALL resolve configuration keys by prefix using the alias "config".
28+ * For example, a request for "config.db.host" will attempt to fetch the key "db.host" from the underlying ConfigInterface.
29+ *
30+ * Identifiers such as 'config', ConfigInterface::class, and the concrete config class MUST return the configuration instance itself.
31+ * Requests for unknown or invalid identifiers MUST result in a ContainerNotFoundException.
32+ *
33+ * @package FastForward\Config\Container
2834 */
2935final class ConfigContainer implements ContainerInterface
3036{
@@ -37,52 +43,68 @@ final class ConfigContainer implements ContainerInterface
3743 * Constructs a new ConfigContainer instance.
3844 *
3945 * This constructor SHALL wrap an existing ConfigInterface instance and expose it
40- * through PSR-11 `get()` and `has()` methods.
46+ * through PSR-11 `get()` and `has()` methods with namespace-style key resolution .
4147 *
42- * @param ConfigInterface $config the configuration instance to expose as a container
48+ * @param ConfigInterface $config The configuration instance to expose as a container.
4349 */
4450 public function __construct (
4551 private ConfigInterface $ config ,
4652 ) {}
4753
4854 /**
49- * Determines if the container can return an entry for the given identifier.
55+ * Determines whether the container can return an entry for the given identifier.
5056 *
51- * @param string $id identifier of the entry to look for
57+ * This method SHALL return true if:
58+ * - The identifier matches known internal bindings (alias, interface, or class).
59+ * - The identifier is prefixed with 'config' and corresponds to an existing key in the configuration.
5260 *
53- * @return bool TRUE if the entry is known or exists in the configuration, FALSE otherwise
61+ * @param string $id Identifier of the entry to look for.
62+ * @return bool True if the entry can be resolved; false otherwise.
5463 */
5564 public function has (string $ id ): bool
5665 {
57- return $ this ->isResolvedByContainer ($ id )
58- || $ this ->config ->has ($ id );
66+ if ($ this ->isResolvedByContainer ($ id )) {
67+ return true ;
68+ }
69+
70+ if (!str_starts_with ($ id , self ::ALIAS )) {
71+ return false ;
72+ }
73+
74+ return $ this ->config ->has (mb_substr ($ id , mb_strlen (self ::ALIAS ) + 1 ));
5975 }
6076
6177 /**
6278 * Retrieves an entry of the container by its identifier.
6379 *
64- * If the ID matches the container itself or the config class, it SHALL return itself.
65- * Otherwise, it SHALL retrieve the value from the configuration.
66- * If the key is not found, it MUST throw a ContainerNotFoundException.
67- *
68- * @param string $id identifier of the entry to retrieve
80+ * This method SHALL resolve identifiers in the following order:
81+ * - If the identifier matches 'config', ConfigInterface::class, or the concrete config class,
82+ * it SHALL return the ConfigInterface instance itself.
83+ * - If the identifier is prefixed with 'config.', the suffix SHALL be used to query the configuration.
84+ * If the configuration key exists, its value SHALL be returned.
85+ * - If the identifier cannot be resolved, a ContainerNotFoundException MUST be thrown.
6986 *
70- * @return mixed the value associated with the identifier
87+ * @param string $id Identifier of the entry to retrieve.
88+ * @return mixed The value associated with the identifier.
7189 *
72- * @throws ContainerNotFoundException if the identifier is not found
90+ * @throws ContainerNotFoundException If the identifier cannot be resolved.
7391 */
7492 public function get (string $ id )
7593 {
76- if ($ id === self ::class ) {
94+ if (self ::class === $ id ) {
7795 return $ this ;
7896 }
7997
8098 if ($ this ->isResolvedByContainer ($ id )) {
8199 return $ this ->config ;
82100 }
83101
84- if ($ this ->config ->has ($ id )) {
85- return $ this ->config ->get ($ id );
102+ if (str_starts_with ($ id , self ::ALIAS )) {
103+ $ id = mb_substr ($ id , mb_strlen (self ::ALIAS ) + 1 );
104+
105+ if ($ this ->config ->has ($ id )) {
106+ return $ this ->config ->get ($ id );
107+ }
86108 }
87109
88110 throw ContainerNotFoundException::forKey ($ id );
@@ -91,16 +113,13 @@ public function get(string $id)
91113 /**
92114 * Determines whether the given identifier is resolved internally by the container itself.
93115 *
94- * This method SHALL be used to check if the requested identifier corresponds to:
95- * - the container alias (e.g., 'config'),
96- * - the Config interface (`FastForward\Config\ConfigInterface`),
97- * - or the concrete configuration key.
98- *
99- * If any of these conditions match, the container MUST resolve the request by returning itself.
100- *
101- * @param string $id the identifier being checked for internal resolution
116+ * This method SHALL match the identifier against:
117+ * - the alias "config"
118+ * - the ConfigInterface::class string
119+ * - the concrete class of the injected configuration instance
102120 *
103- * @return bool TRUE if the container SHALL resolve the identifier itself; FALSE otherwise
121+ * @param string $id The identifier to check.
122+ * @return bool True if the identifier is resolved internally; false otherwise.
104123 */
105124 private function isResolvedByContainer (string $ id ): bool
106125 {
0 commit comments