Skip to content

Commit 0ec4178

Browse files
committed
Initial commit
0 parents  commit 0ec4178

42 files changed

Lines changed: 1800 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea/
2+
composer.lock
3+
vendor/

LICENSE.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# License
2+
3+
This project is licensed under the terms of the MIT license.
4+
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2023 [CommonPHP.org](https://www.commonphp.org/)
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a copy
10+
of this software and associated documentation files (the "Software"), to deal
11+
in the Software without restriction, including without limitation the rights
12+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
copies of the Software, and to permit persons to whom the Software is
14+
furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included in all
17+
copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
SOFTWARE.

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# CommonPHP Dependency Injection Library
2+
3+
This library provides a straightforward way to manage service dependencies in a PHP application. It follows the Inversion of Control principle, allowing classes to specify their dependencies without being responsible for their creation.
4+
5+
## Features
6+
7+
1. **Dependency Injection**: Enables classes to declare their dependencies in the constructor, which will be automatically injected when the class is instantiated.
8+
9+
2. **Service Container**: The library includes a service container that manages service instances. Services are created as singletons - once a service is created, the same instance will be returned every time it is requested.
10+
11+
3. **Simple API**: The library provides simple and intuitive methods for registering services and retrieving them from the service container.
12+
13+
## Usage
14+
15+
Here is a simple example of how to use the library:
16+
17+
```php
18+
class MyClass {
19+
public function __construct(CommonPHP\DependencyInjection\ServiceContainer $container)
20+
{
21+
// The service container is injected as a dependency
22+
}
23+
}
24+
25+
$di = new CommonPHP\DependencyInjection\DependencyInjector();
26+
$container = new CommonPHP\DependencyInjection\ServiceContainer($di);
27+
28+
// Register your services
29+
$di->services->register(MyClass::class);
30+
31+
// Retrieve the service
32+
$myClassInstance = $container->get(MyClass::class);
33+
```
34+
35+
This library is designed to prevent direct dependency on the `DependencyInjector` inside services. The `DependencyInjector` should only be used during application bootstrapping.
36+
37+
## Installation
38+
39+
This section outlines how to install the `CommonPHP Dependency Injection` library.
40+
41+
### Requirements
42+
43+
- PHP 8.1 or newer.
44+
45+
### With Composer
46+
47+
The easiest way to install the `CommonPHP Dependency Injection` library is via Composer.
48+
49+
If you don't have Composer installed, you can download it from [https://getcomposer.org/](https://getcomposer.org/).
50+
51+
Once you have Composer installed, you can install the `CommonPHP Dependency Injection` library by running the following command in your terminal:
52+
53+
```bash
54+
composer require comphp/di
55+
```
56+
57+
This command will add the `CommonPHP Dependency Injection` library as a dependency to your project, and Composer will automatically handle the autoloading of classes.
58+
59+
### Manual Installation
60+
61+
If you don't use Composer, you can download the latest release of the `CommonPHP Dependency Injection` library from the GitHub repository. After downloading, you will have to handle autoloading the classes manually in your application.
62+
63+
After the installation, you can use the library as outlined in the Usage section.
64+
65+
## Next Steps
66+
67+
After the installation, refer to the Usage section of this README to learn how to use the `CommonPHP Dependency Injection` library in your projects.
68+
69+
## Testing
70+
71+
As of version 0.0.1, we are still in the process of refining the codebase and defining the overall functionality of the CommonPHP Dependency Injection library, as well as other libraries within the CommonPHP framework. Therefore, comprehensive unit tests have not been created yet.
72+
73+
However, quality and reliability are paramount to us. Rest assured, we plan to incorporate robust testing in future versions as the functionality becomes more concrete. In the meantime, we encourage contributions in all areas of the project, including tests.
74+
75+
If you are interested in contributing to testing, or any other aspect of this project, please see the 'Contributing' section for more information.
76+
77+
78+
## License
79+
80+
This project is licensed under the MIT License. See the [LICENSE.md](LICENSE.md) file for details.

composer.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "comphp/di",
3+
"type": "library",
4+
"version": "0.0.1",
5+
"license": "MIT",
6+
"authors": [
7+
{
8+
"name": "timothy.mcclatchey",
9+
"email": "timothy@commonphp.org"
10+
}
11+
],
12+
"autoload": {
13+
"psr-4": {
14+
"CommonPHP\\DependencyInjection\\": "src/"
15+
}
16+
},
17+
"autoload-dev": {
18+
"psr-4": {
19+
"Test\\CommonPHP\\DependencyInjection\\": "tests/"
20+
}
21+
},
22+
"require": {
23+
"php": "^8.1"
24+
},
25+
"require-dev": {
26+
"phpunit/phpunit": "^9.5.23"
27+
}
28+
}

examples/usage.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
include '../vendor/autoload.php';
4+
5+
class InstantiateExample1
6+
{
7+
public function __construct(CommonPHP\DependencyInjection\ServiceContainer $container)
8+
{
9+
// This is the expected usage, and will work. The DI will not expose itself
10+
}
11+
}
12+
13+
class InstantiateExample2
14+
{
15+
public function __construct(CommonPHP\DependencyInjection\DependencyInjector $di)
16+
{
17+
// This instantiate will fail because DI will never expose itself. DI is only used during application bootstrapping
18+
// then the ServiceContainer auto-registers itself as service and provides a simplified readonly method of handling
19+
// services
20+
}
21+
}
22+
23+
$di = new CommonPHP\DependencyInjection\DependencyInjector();
24+
$container = new CommonPHP\DependencyInjection\ServiceContainer($di);
25+
26+
// This is a simulated "bootstrapping"
27+
$di->services->register(InstantiateExample1::class);
28+
$di->services->register(InstantiateExample2::class);
29+
30+
$ex1 = $container->get(InstantiateExample1::class); // This will work
31+
$ex2 = $container->get(InstantiateExample2::class); // This will not
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace CommonPHP\DependencyInjection\Collections;
4+
5+
use CommonPHP\DependencyInjection\Exceptions\AliasAlreadyRegisteredException;
6+
use CommonPHP\DependencyInjection\Exceptions\AliasClassNotDerivedException;
7+
use CommonPHP\DependencyInjection\Exceptions\AliasClassNotFoundException;
8+
use CommonPHP\DependencyInjection\Exceptions\AliasNotRegisteredException;
9+
use CommonPHP\DependencyInjection\Exceptions\ServiceClassNotFoundException;
10+
11+
/**
12+
* The AliasCollection class represents a collection of aliases.
13+
*/
14+
final class AliasCollection
15+
{
16+
/**
17+
* The array of aliases.
18+
*
19+
* @var array
20+
*/
21+
private array $aliases = [];
22+
23+
/**
24+
* Check if an alias exists in the collection.
25+
*
26+
* @param string $aliasClass The class name of the alias.
27+
* @return bool True if the alias exists, false otherwise.
28+
*/
29+
public function has(string $aliasClass): bool
30+
{
31+
return array_key_exists($aliasClass, $this->aliases);
32+
}
33+
34+
/**
35+
* Get the class name associated with an alias.
36+
*
37+
* @param string $aliasClass The class name of the alias.
38+
* @return string The class name associated with the alias.
39+
* @throws AliasNotRegisteredException If the alias is not found in the collection.
40+
*/
41+
public function get(string $aliasClass): string
42+
{
43+
if (!$this->has($aliasClass)) {
44+
throw new AliasNotRegisteredException($aliasClass);
45+
}
46+
return $this->aliases[$aliasClass];
47+
}
48+
49+
/**
50+
* Register an alias with a class name.
51+
*
52+
* @param string $aliasClass The class name of the alias.
53+
* @param string $serviceClass The class name associated with the alias.
54+
* @return void
55+
* @throws AliasAlreadyRegisteredException If the alias is already registered with a different class.
56+
* @throws ServiceClassNotFoundException If the service class is not found.
57+
* @throws AliasClassNotFoundException If the alias class is not found.
58+
* @throws AliasClassNotDerivedException If the alias class and service class are not derived from each other.
59+
*/
60+
public function register(string $aliasClass, string $serviceClass): void
61+
{
62+
if ($this->has($aliasClass)) {
63+
throw new AliasAlreadyRegisteredException($aliasClass, $serviceClass, $this->aliases[$aliasClass]);
64+
}
65+
66+
if (!class_exists($serviceClass)) {
67+
throw new ServiceClassNotFoundException($serviceClass);
68+
}
69+
70+
if (!class_exists($aliasClass)) {
71+
throw new AliasClassNotFoundException($aliasClass);
72+
}
73+
74+
if (!is_subclass_of($aliasClass, $serviceClass) && !is_subclass_of($serviceClass, $aliasClass)) {
75+
throw new AliasClassNotDerivedException($aliasClass, $serviceClass);
76+
}
77+
78+
$this->aliases[$aliasClass] = $serviceClass;
79+
}
80+
81+
/**
82+
* Get all aliases as an array.
83+
*
84+
* @return array The aliases as an array.
85+
*/
86+
public function toArray(): array
87+
{
88+
return $this->aliases;
89+
}
90+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
namespace CommonPHP\DependencyInjection\Collections;
4+
5+
use CommonPHP\DependencyInjection\Exceptions\NamespaceAlreadyRegisteredException;
6+
use CommonPHP\DependencyInjection\Exceptions\NamespaceInvalidException;
7+
8+
/**
9+
* The NamespaceCollection class represents a collection of namespaces.
10+
*/
11+
final class NamespaceCollection
12+
{
13+
/**
14+
* The array of namespaces.
15+
*
16+
* @var array
17+
*/
18+
private array $namespaces = [];
19+
20+
/**
21+
* Check if a class belongs to any registered namespace.
22+
*
23+
* @param string $className The fully qualified class name.
24+
* @return bool True if the class belongs to any registered namespace, false otherwise.
25+
*/
26+
public function has(string $className): bool
27+
{
28+
foreach ($this->namespaces as $namespace) {
29+
if (str_starts_with($className, $namespace)) {
30+
return true;
31+
}
32+
}
33+
return false;
34+
}
35+
36+
/**
37+
* Register a namespace.
38+
*
39+
* @param string $namespace The namespace to register.
40+
* @return void
41+
* @throws NamespaceInvalidException If the namespace is not a valid PHP namespace.
42+
* @throws NamespaceAlreadyRegisteredException If the namespace is already registered.
43+
*/
44+
public function register(string $namespace): void
45+
{
46+
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9_\\\\]*$/m', $namespace)) {
47+
throw new NamespaceInvalidException($namespace);
48+
}
49+
50+
if (!str_ends_with($namespace, "\\")) {
51+
$namespace .= "\\";
52+
}
53+
54+
// If the namespace is already registered, throw an exception
55+
if (in_array($namespace, $this->namespaces)) {
56+
throw new NamespaceAlreadyRegisteredException($namespace);
57+
}
58+
59+
// Register the namespace.
60+
$this->namespaces[] = $namespace;
61+
}
62+
63+
/**
64+
* Get all registered namespaces as an array.
65+
*
66+
* @return array The registered namespaces.
67+
*/
68+
public function toArray(): array
69+
{
70+
return $this->namespaces;
71+
}
72+
}

0 commit comments

Comments
 (0)