Test Failed
Branch master (33f0fa)
by Divine Niiquaye
02:33
created

AnnotationExtension::getConfigTreeBuilder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 28
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 33
rs 9.472
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 2019 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\Extensions;
19
20
use Biurad\Annotations\AnnotationLoader;
21
use Biurad\Annotations\ListenerInterface;
22
use Doctrine\Common\Annotations\AnnotationReader;
23
use Doctrine\Common\Annotations\AnnotationRegistry;
24
use Doctrine\Common\Annotations\PsrCachedReader;
25
use Flight\Routing\Annotation\Route;
26
use Flight\Routing\RouteCollection;
27
use Rade\DI\AbstractContainer;
28
use Rade\DI\Definition;
29
use Rade\DI\Definitions\Reference;
30
use Rade\DI\Definitions\Statement;
31
use Rade\DI\Services\AliasedInterface;
32
use Spiral\Attributes\AnnotationReader as DoctrineReader;
33
use Spiral\Attributes\AttributeReader;
34
use Spiral\Attributes\Composite\MergeReader;
35
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
36
use Symfony\Component\Config\Definition\ConfigurationInterface;
37
38
/**
39
 * Biurad Annotation Extension.
40
 *
41
 * @author Divine Niiquaye Ibok <[email protected]>
42
 */
43
class AnnotationExtension implements AliasedInterface, BootExtensionInterface, ConfigurationInterface, ExtensionInterface
44
{
45
    /**
46
     * {@inheritdoc}
47
     */
48
    public function getAlias(): string
49
    {
50
        return 'annotation';
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function getConfigTreeBuilder(): TreeBuilder
57
    {
58
        $treeBuilder = new TreeBuilder(__CLASS__);
59
60
        $treeBuilder->getRootNode()
61
            ->children()
62
                ->scalarNode('use_reader')->end()
63
                ->variableNode('class_loader')
64
                    ->beforeNormalization()
65
                        ->ifTrue(fn ($v): bool => !\is_callable($v))
66
                        ->thenInvalid('Class loader must be a class invoker or a callable')
67
                    ->end()
68
                ->end()
69
                ->arrayNode('listeners')
70
                    ->beforeNormalization()->ifString()->then(fn ($v) => [$v])->end()
71
                    ->prototype('scalar')->end()
72
                    ->defaultValue([])
73
                ->end()
74
                ->arrayNode('resources')
75
                    ->beforeNormalization()->ifString()->then(fn ($v) => [$v])->end()
76
                    ->prototype('scalar')->end()
77
                    ->defaultValue([])
78
                ->end()
79
                ->arrayNode('doctrine_ignores')
80
                    ->beforeNormalization()->ifString()->then(fn ($v) => [$v])->end()
81
                    ->prototype('scalar')->end()
82
                    ->defaultValue(['persistent', 'serializationVersion', 'inject'])
83
                ->end()
84
                ->scalarNode('cache')->end()
85
            ->end()
86
        ;
87
88
        return $treeBuilder;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function register(AbstractContainer $container, array $configs = []): void
95
    {
96
        $loader = $container->autowire('annotation.loader', new Definition(AnnotationLoader::class));
97
98
        if (isset($configs['class_loader'])) {
99
            $loader->arg(1, $configs['class_loader']);
100
        }
101
102
        if (!empty($resources = $configs['resources'] ?? [])) {
103
            $loader->bind('resource', [$resources]);
104
        }
105
106
        if (isset($configs['use_reader'])) {
107
            $loader->arg(0, $container->has($configs['use_reader']) ? new Reference($configs['use_reader']) : new Statement($configs['use_reader']));
108
            $attribute = AttributeReader::class;
109
110
            if (null !== \class_exists(AnnotationReader::class)) {
111
                $doctrineService = AnnotationReader::class;
112
113
                if ($container->has('psr6.cache')) {
114
                    $doctrineService = PsrCachedReader::class;
115
                    $doctrineArgs = [new Statement($doctrineService), $container->get('psr6.cache'), $container->parameter('debug')];
116
                }
117
118
                $doctrineService = $container->autowire('annotation.doctrine', new Definition($doctrineService, $doctrineArgs ?? []));
119
120
                foreach ($configs['doctrine_ignores'] as $doctrineExclude) {
121
                    $doctrineService->bind('addGlobalIgnoredName', $doctrineExclude);
122
                }
123
124
                //$attribute = new MergeReader([$reader, new DoctrineReader($app['annotation.doctrine'])]);
125
                $attributeArgs = [[new Statement($attribute), new Statement(DoctrineReader::class)]];
126
                $attribute = MergeReader::class;
127
128
                // doctrine/annotations ^1.0 compatibility.
129
                if (\method_exists(AnnotationRegistry::class, 'registerLoader')) {
130
                    AnnotationRegistry::registerUniqueLoader('class_exists');
131
                }
132
            }
133
134
            $container->autowire('annotation.reader', new Definition($attribute, $attributeArgs ?? []));
135
        }
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    public function boot(AbstractContainer $container): void
142
    {
143
        $loader = $container->definition('annotation.loader');
144
        $listeners = $container->findBy(ListenerInterface::class, fn (string $listenerId) => new Reference($listenerId));
145
146
        if ($loader instanceof AnnotationLoader) {
147
            $loader->listener(...$container->getResolver()->resolveArguments($listeners));
148
        } else {
149
            $loader->bind('listener', [$listeners]);
150
        }
151
152
        if ($container->hasExtension(RoutingExtension::class)) {
153
            $container->set('router.annotation.collection', new Definition([new Reference('annotation.loader'), 'load'], [Route::class, false]))
154
                ->autowire([RouteCollection::class]);
155
        }
156
    }
157
}
158