Admin
1 month ago
Amplitude
1 month ago
Api
1 month ago
Blocks
2 months ago
Dto
6 months ago
Integrations
1 month ago
Jobs
4 months ago
Models
7 months ago
Providers
1 month ago
Repositories
7 months ago
Setup
1 month ago
Tracking
7 months ago
Boot.php
1 month ago
Container.php
10 months ago
Functions.php
3 months ago
Container.php
131 lines
| 1 | <?php |
| 2 | |
| 3 | namespace Hostinger\Reach; |
| 4 | |
| 5 | use Psr\Container\ContainerInterface; |
| 6 | use Closure; |
| 7 | use ReflectionException; |
| 8 | use ReflectionClass; |
| 9 | use ReflectionMethod; |
| 10 | use Exception; |
| 11 | |
| 12 | class Container implements ContainerInterface { |
| 13 | protected array $entries = array(); |
| 14 | protected array $instances = array(); |
| 15 | protected array $rules = array(); |
| 16 | |
| 17 | public function get( mixed $id ): mixed { |
| 18 | if ( ! $this->has( $id ) ) { |
| 19 | $this->set( $id ); |
| 20 | } |
| 21 | |
| 22 | if ( $this->entries[ $id ] instanceof Closure || is_callable( $this->entries[ $id ] ) ) { |
| 23 | return $this->entries[ $id ]( $this ); |
| 24 | } |
| 25 | |
| 26 | if ( isset( $this->rules['shared'] ) && in_array( $id, $this->rules['shared'], true ) ) { |
| 27 | return $this->singleton( $id ); |
| 28 | } |
| 29 | |
| 30 | return $this->resolve( $id ); |
| 31 | } |
| 32 | |
| 33 | public function has( mixed $id ): bool { |
| 34 | return isset( $this->entries[ $id ] ); |
| 35 | } |
| 36 | |
| 37 | public function set( mixed $entry, mixed $concrete = null ): void { |
| 38 | if ( is_null( $concrete ) ) { |
| 39 | $concrete = $entry; |
| 40 | } |
| 41 | $this->entries[ $entry ] = $concrete; |
| 42 | } |
| 43 | |
| 44 | public function resolve( mixed $alias ): mixed { |
| 45 | $reflector = $this->getReflector( $alias ); |
| 46 | $constructor = $reflector->getConstructor(); |
| 47 | if ( $reflector->isInterface() ) { |
| 48 | return $this->resolveInterface( $reflector ); |
| 49 | } |
| 50 | if ( ! $reflector->isInstantiable() ) { |
| 51 | throw new Exception( |
| 52 | esc_html( "Cannot inject {$reflector->getName()} because it cannot be instantiated" ) |
| 53 | ); |
| 54 | } |
| 55 | if ( $constructor === null ) { |
| 56 | return $reflector->newInstance(); |
| 57 | } |
| 58 | $args = $this->getArguments( $alias, $constructor ); |
| 59 | |
| 60 | return $reflector->newInstanceArgs( $args ); |
| 61 | } |
| 62 | |
| 63 | public function singleton( mixed $alias ): mixed { |
| 64 | if ( ! isset( $this->instances[ $alias ] ) ) { |
| 65 | $this->instances[ $alias ] = $this->resolve( |
| 66 | $this->entries[ $alias ] |
| 67 | ); |
| 68 | } |
| 69 | |
| 70 | return $this->instances[ $alias ]; |
| 71 | } |
| 72 | |
| 73 | public function getReflector( string $alias ): ReflectionClass { |
| 74 | $class = $this->entries[ $alias ]; |
| 75 | try { |
| 76 | return ( new ReflectionClass( $class ) ); |
| 77 | } catch ( ReflectionException $e ) { |
| 78 | throw new Exception( |
| 79 | esc_html( $e->getMessage() ), |
| 80 | esc_html( $e->getCode() ) |
| 81 | ); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | public function getArguments( mixed $alias, ReflectionMethod $constructor ): array { |
| 86 | $args = array(); |
| 87 | $params = $constructor->getParameters(); |
| 88 | |
| 89 | foreach ( $params as $param ) { |
| 90 | $type = $param->getType(); |
| 91 | |
| 92 | if ( $type && ! $type->isBuiltin() ) { |
| 93 | $class_name = $type->getName(); |
| 94 | $args[] = $this->get( $class_name ); |
| 95 | } elseif ( $param->isDefaultValueAvailable() ) { |
| 96 | $args[] = $param->getDefaultValue(); |
| 97 | } elseif ( isset( $this->rules[ $alias ][ $param->getName() ] ) ) { |
| 98 | $args[] = $this->rules[ $alias ][ $param->getName() ]; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | return $args; |
| 103 | } |
| 104 | |
| 105 | public function resolveInterface( ReflectionClass $reflector ): mixed { |
| 106 | if ( isset( $this->rules['substitute'][ $reflector->getName() ] ) ) { |
| 107 | return $this->get( |
| 108 | $this->rules['substitute'][ $reflector->getName() ] |
| 109 | ); |
| 110 | } |
| 111 | |
| 112 | $classes = get_declared_classes(); |
| 113 | foreach ( $classes as $class ) { |
| 114 | $rf = new ReflectionClass( $class ); |
| 115 | if ( $rf->implementsInterface( $reflector->getName() ) ) { |
| 116 | return $this->get( $rf->getName() ); |
| 117 | } |
| 118 | } |
| 119 | throw new Exception( |
| 120 | esc_html( "Class {$reflector->getName()} not found" ), |
| 121 | 1 |
| 122 | ); |
| 123 | } |
| 124 | |
| 125 | public function configure( array $config ): static { |
| 126 | $this->rules = array_merge( $this->rules, $config ); |
| 127 | |
| 128 | return $this; |
| 129 | } |
| 130 | } |
| 131 |