divineniiquaye /
rade-di
| 1 | <?php |
||||
| 2 | |||||
| 3 | declare(strict_types=1); |
||||
| 4 | |||||
| 5 | /* |
||||
| 6 | * This file is part of DivineNii opensource projects. |
||||
| 7 | * |
||||
| 8 | * PHP version 7.4 and above required |
||||
| 9 | * |
||||
| 10 | * @author Divine Niiquaye Ibok <[email protected]> |
||||
| 11 | * @copyright 2021 DivineNii (https://divinenii.com/) |
||||
| 12 | * @license https://opensource.org/licenses/BSD-3-Clause License |
||||
| 13 | * |
||||
| 14 | * For the full copyright and license information, please view the LICENSE |
||||
| 15 | * file that was distributed with this source code. |
||||
| 16 | */ |
||||
| 17 | |||||
| 18 | namespace Rade\DI\Facade; |
||||
| 19 | |||||
| 20 | use PhpParser\BuilderFactory; |
||||
| 21 | use PhpParser\Node\{ |
||||
| 22 | Expr\StaticPropertyFetch, |
||||
| 23 | Name, |
||||
| 24 | Stmt\Declare_, |
||||
| 25 | Stmt\DeclareDeclare, |
||||
| 26 | Stmt\Return_, |
||||
| 27 | UnionType |
||||
| 28 | }; |
||||
| 29 | use Psr\Container\ContainerInterface; |
||||
| 30 | use Rade\DI\Builder\CodePrinter; |
||||
| 31 | use Rade\DI\{ContainerBuilder, Definition}; |
||||
| 32 | |||||
| 33 | /** |
||||
| 34 | * A Proxy manager for implementing laravel like facade system. |
||||
| 35 | * |
||||
| 36 | * @author Divine Niiquaye Ibok <[email protected]> |
||||
| 37 | */ |
||||
| 38 | class FacadeProxy |
||||
| 39 | { |
||||
| 40 | private ContainerInterface $container; |
||||
| 41 | |||||
| 42 | /** @var array<string,string> */ |
||||
| 43 | private array $proxies = []; |
||||
| 44 | |||||
| 45 | 2 | public function __construct(ContainerInterface $container) |
|||
| 46 | { |
||||
| 47 | 2 | $this->container = $container; |
|||
| 48 | 2 | } |
|||
| 49 | |||||
| 50 | /** |
||||
| 51 | * Register(s) service{s) found in container as shared proxy facade(s). |
||||
| 52 | */ |
||||
| 53 | 2 | public function proxy(string ...$services): void |
|||
| 54 | { |
||||
| 55 | 2 | foreach ($services as $service) { |
|||
| 56 | 2 | $id = \str_replace(['.', '_', '\\'], '', \lcfirst(\ucwords($service, '._'))); |
|||
| 57 | |||||
| 58 | 2 | if (!$this->container instanceof ContainerBuilder) { |
|||
| 59 | 1 | Facade::$proxies[$id] = $service; |
|||
| 60 | |||||
| 61 | 1 | continue; |
|||
| 62 | } |
||||
| 63 | |||||
| 64 | 1 | $this->proxies[$id] = $service; |
|||
| 65 | } |
||||
| 66 | 2 | } |
|||
| 67 | |||||
| 68 | /** |
||||
| 69 | * This build method works with container builder. |
||||
| 70 | * |
||||
| 71 | * @param string $className for compiled facade class |
||||
| 72 | */ |
||||
| 73 | 2 | public function build(string $className = 'Facade'): ?string |
|||
| 74 | { |
||||
| 75 | /** @var ContainerBuilder */ |
||||
| 76 | 2 | $container = $this->container; |
|||
| 77 | |||||
| 78 | 2 | if ([] !== $proxiedServices = $this->proxies) { |
|||
| 79 | 1 | $astNodes = []; |
|||
| 80 | 1 | $builder = $container->getBuilder(); |
|||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 81 | 1 | \ksort($proxiedServices); |
|||
| 82 | |||||
| 83 | 1 | $astNodes[] = new Declare_([new DeclareDeclare('strict_types', $builder->val(1))]); |
|||
| 84 | 1 | $classNode = $builder->class($className)->extend('\Rade\DI\Facade\Facade')->setDocComment(CodePrinter::COMMENT); |
|||
| 85 | |||||
| 86 | 1 | $classNode->addStmts($this->resolveProxies($container, $builder, $proxiedServices)); |
|||
| 87 | 1 | $astNodes[] = $classNode->getNode(); |
|||
| 88 | |||||
| 89 | 1 | return CodePrinter::print($astNodes); |
|||
| 90 | } |
||||
| 91 | |||||
| 92 | 1 | return null; |
|||
| 93 | } |
||||
| 94 | |||||
| 95 | /** |
||||
| 96 | * This method resolves the proxies from container builder. |
||||
| 97 | * |
||||
| 98 | * @param string[] $proxiedServices |
||||
| 99 | * |
||||
| 100 | * @return \PhpParser\Builder\Method[] |
||||
| 101 | */ |
||||
| 102 | 1 | protected function resolveProxies(ContainerBuilder $container, BuilderFactory $builder, array $proxiedServices): array |
|||
| 103 | { |
||||
| 104 | 1 | $builtProxies = []; |
|||
| 105 | |||||
| 106 | 1 | foreach ($proxiedServices as $method => $proxy) { |
|||
| 107 | 1 | if (!$container->has($proxy)) { |
|||
| 108 | 1 | continue; |
|||
| 109 | } |
||||
| 110 | |||||
| 111 | 1 | $definition = $container->service($proxy); |
|||
| 112 | 1 | $proxyNode = $builder->method($method)->makePublic()->makeStatic(); |
|||
| 113 | |||||
| 114 | 1 | if ($definition instanceof Definition) { |
|||
| 115 | 1 | if (!$definition->isPublic()) { |
|||
| 116 | 1 | continue; |
|||
| 117 | } |
||||
| 118 | |||||
| 119 | 1 | if (!empty($type = $definition->getType())) { |
|||
| 120 | 1 | $proxyNode->setReturnType(\is_array($type) ? new UnionType(\array_map(fn ($type) => new Name($type), $type)) : $type); |
|||
|
0 ignored issues
–
show
It seems like
is_array($type) ? new Ph.... */ }, $type)) : $type can also be of type PhpParser\Node\UnionType; however, parameter $type of PhpParser\Builder\FunctionLike::setReturnType() does only seem to accept PhpParser\Node\Name|PhpP...ode\NullableType|string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 121 | } |
||||
| 122 | } |
||||
| 123 | |||||
| 124 | 1 | $body = $builder->methodCall(new StaticPropertyFetch(new Name('self'), 'container'), 'get', [$proxy]); |
|||
| 125 | 1 | $builtProxies[] = $proxyNode->addStmt(new Return_($body)); |
|||
| 126 | } |
||||
| 127 | |||||
| 128 | 1 | return $builtProxies; |
|||
| 129 | } |
||||
| 130 | } |
||||
| 131 |