Passed
Push — master ( c5bd37...640ffc )
by
unknown
05:22
created

ApiResourceServiceProvider::addOpenApiServices()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 19
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 31
rs 9.6333
1
<?php
2
3
namespace W2w\Laravel\Apie\Providers;
4
5
use Illuminate\Support\ServiceProvider;
6
use Madewithlove\IlluminatePsrCacheBridge\Laravel\CacheItemPool;
0 ignored issues
show
Bug introduced by
The type Madewithlove\IlluminateP...e\Laravel\CacheItemPool was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
8
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
9
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
10
use Symfony\Component\Serializer\Serializer;
11
use Symfony\Component\Serializer\SerializerInterface;
12
use W2w\Laravel\Apie\Plugins\Illuminate\DataLayers\StatusFromDatabaseRetriever;
13
use W2w\Laravel\Apie\Plugins\Illuminate6Cache\Illuminate6CachePlugin;
14
use W2w\Laravel\Apie\Plugins\Illuminate6Cache\PsrCacheBridgePlugin;
15
use W2w\Laravel\Apie\Plugins\Illuminate\IlluminatePlugin;
16
use W2w\Laravel\Apie\Services\ApieContext;
17
use W2w\Laravel\Apie\Services\ApieExceptionToResponse;
18
use W2w\Laravel\Apie\Services\DispatchOpenApiSpecGeneratedEvent;
0 ignored issues
show
Bug introduced by
The type W2w\Laravel\Apie\Service...enApiSpecGeneratedEvent was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use W2w\Laravel\Apie\Services\FileStorageDataLayerContainer;
20
use W2w\Lib\Apie\Apie;
21
use W2w\Lib\Apie\Core\ApiResourceFacade;
22
use W2w\Lib\Apie\Core\ClassResourceConverter;
23
use W2w\Lib\Apie\Core\Resources\ApiResources;
24
use W2w\Lib\Apie\Core\Resources\ApiResourcesInterface;
25
use W2w\Lib\Apie\DefaultApie;
26
use W2w\Lib\Apie\Exceptions\InvalidClassTypeException;
27
use W2w\Lib\Apie\Interfaces\ResourceSerializerInterface;
28
use W2w\Lib\Apie\OpenApiSchema\OpenApiSpecGenerator;
29
use W2w\Lib\Apie\Plugins\ApplicationInfo\DataLayers\ApplicationInfoRetriever;
30
use W2w\Lib\Apie\Plugins\Core\Serializers\SymfonySerializerAdapter;
31
use W2w\Lib\Apie\Plugins\FakeAnnotations\FakeAnnotationsPlugin;
32
use W2w\Lib\Apie\Plugins\FileStorage\DataLayers\FileStorageDataLayer;
33
use W2w\Lib\Apie\Plugins\Mock\MockPlugin;
34
use W2w\Lib\Apie\Plugins\StatusCheck\DataLayers\StatusCheckRetriever;
35
36
/**
37
 * Install apie classes to Laravel.
38
 */
39
class ApiResourceServiceProvider extends ServiceProvider
40
{
41
    /**
42
     * Perform post-registration booting of services.
43
     *
44
     * @return void
45
     */
46
    public function boot()
47
    {
48
        if (function_exists('config_path')) {
49
            $this->publishes(
50
                [
51
                    __DIR__ . '/../../config/apie.php' => config_path('apie.php'),
52
                ]
53
            );
54
        }
55
56
        $this->loadMigrationsFrom(__DIR__ . '/../../migrations');
57
    }
58
59
    /**
60
     * Register any application services.
61
     */
62
    public function register()
63
    {
64
        $this->bindApieContextServices();
65
        $this->bindApieServices();
66
67
        if (strpos($this->app->version(), 'Lumen') === false) {
68
            $this->app->register(ApieLaravelServiceProvider::class);
69
        } else {
70
            $this->app->register(ApieLumenServiceProvider::class);
71
        }
72
73
        $this->addStatusResourceServices();
74
    }
75
76
    /**
77
     * Bind all Apie related services that are on application level. They must be singletons and are not checking
78
     * at the current active Apie instance.
79
     */
80
    private function bindApieContextServices()
81
    {
82
        /**
83
         * apie.config: main config
84
         */
85
        $this->app->singleton('apie.config', function () {
86
            $config = $this->app->get('config');
87
            $res = ApieConfigResolver::resolveConfig($config->get('apie') ?? []);
88
            $config->set('apie', $res);
89
            return $res;
90
        });
91
92
        /**
93
         * apie.plugins: array of Apie plugins of the main apie instance.
94
         */
95
        $this->app->singleton('apie.plugins', function () {
96
            return $this->getPlugins();
97
        });
98
99
        /**
100
         * ApieContext::class: get all Apie instances and see which is the current Apie instance.
101
         */
102
        $this->app->singleton(ApieContext::class, function () {
103
            $plugins = $this->app->get('apie.plugins');
104
            $debug = (bool) config('app.debug');
105
            $config = $this->app->get('apie.config');
106
            $cacheFolder = storage_path('app/apie-cache');
107
            $apie = DefaultApie::createDefaultApie($debug, $plugins, $cacheFolder, false);
108
            return new ApieContext($this->app, $apie, $config, $config['contexts']);
109
        });
110
111
        /**
112
         * FileStorageDataLayerContainer::class: creates FileStorageDataLayer for the right Apie instance.
113
         */
114
        $this->app->singleton(FileStorageDataLayerContainer::class, function () {
115
            return new FileStorageDataLayerContainer(
116
                storage_path('app/api-file-storage'),
117
                $this->app->get(ApieContext::class)
118
            );
119
        });
120
    }
121
122
    private function getPlugins(): array
123
    {
124
        $plugins = [];
125
        $config = $this->app->get('apie.config');
126
        if (!empty($config['mock'])) {
127
            $plugins[] = new MockPlugin($config['mock-skipped-resources']);
128
        }
129
        foreach ($this->app->tagged(Apie::class) as $plugin) {
130
            $plugins[] = $plugin;
131
        }
132
        foreach ($config['plugins'] as $plugin) {
133
            $plugins[] = $this->app->make($plugin);
134
        }
135
        if (!empty($config['resource-config'])) {
136
            $plugins[] = new FakeAnnotationsPlugin($config['resource-config']);
137
        }
138
        if (!empty($config['caching'])) {
139
            if ($this->app->bound('cache.psr6')) {
140
                $plugins[] = new Illuminate6CachePlugin($this->app);
141
            } elseif (class_exists(CacheItemPool::class)) {
142
                $plugins[] = new PsrCacheBridgePlugin($this->app);
143
            }
144
        }
145
        $plugins[] = new IlluminatePlugin($this->app, $config);
146
        return $plugins;
147
    }
148
149
    private function bindApieServices()
150
    {
151
        /**
152
         * ApiResourcesInterface::class: get all resources of the current Apie instance.
153
         */
154
        $this->app->bind(ApiResourcesInterface::class, function () {
155
            return new ApiResources($this->app->get(Apie::class)->getResources());
156
        });
157
158
        /**
159
         * Apie::class: current Apie instance.
160
         */
161
        $this->app->bind(Apie::class, function () {
162
            /** @var ApieContext $context */
163
            $context = $this->app->get(ApieContext::class)->getActiveContext();
164
            return $context->getApie();
165
        });
166
167
        /**
168
         * IlluminatePlugin::class: current IlluminatePlugin instance
169
         */
170
        $this->app->bind(IlluminatePlugin::class, function () {
171
            /** @var Apie $apie */
172
            $apie = $this->app->get(Apie::class);
173
            return $apie->getPlugin(IlluminatePlugin::class);
174
        });
175
176
        /**
177
         * ApplicationInfoRetriever::class: get retriever for Application Info of current apie instance.
178
         */
179
        $this->app->bind(ApplicationInfoRetriever::class, function () {
180
            /** @var IlluminatePlugin $laravelPlugin */
181
            $laravelPlugin = $this->app->get(IlluminatePlugin::class);
182
            $config = $laravelPlugin->getLaravelConfig();
183
            return new ApplicationInfoRetriever(
184
                config('app.name'),
185
                config('app.env'),
186
                $config['metadata']['hash'],
187
                config('app.debug')
188
            );
189
        });
190
191
        /**
192
         * FileStorageDataLayer::class: get file storage data layer for current apie instance.
193
         */
194
        $this->app->bind(FileStorageDataLayer::class, function () {
195
            return $this->app->get(FileStorageDataLayerContainer::class)->getCurrentFileStorageDataLayer();
196
        });
197
198
        /**
199
         * ApieExceptionToResponse::class: converts exception to an Apie response.
200
         */
201
        $this->app->bind(ApieExceptionToResponse::class, function () {
202
            /** @var IlluminatePlugin $laravelPlugin */
203
            $laravelPlugin = $this->app->get(IlluminatePlugin::class);
204
            $config = $laravelPlugin->getLaravelConfig();
205
            $mapping = $config['exception-mapping'];
206
            return new ApieExceptionToResponse($this->app->make(HttpFoundationFactory::class), $mapping);
207
        });
208
209
        /**
210
         * Serializer::class: gets the Symfony serializer.
211
         */
212
        $this->app->bind(Serializer::class, function () {
213
            $serializer = $this->app->get(ResourceSerializerInterface::class);
214
            if (! ($serializer instanceof SymfonySerializerAdapter)) {
215
                throw new InvalidClassTypeException('resource serializer', SymfonySerializerAdapter::class);
216
            }
217
            return $serializer->getSerializer();
218
        });
219
        $this->app->bind(SerializerInterface::class, Serializer::class);
220
        $this->app->bind(NormalizerInterface::class, Serializer::class);
221
        $this->app->bind(DenormalizerInterface::class, Serializer::class);
222
223
        $todo = [
224
            [ApiResourceFacade::class, 'getApiResourceFacade'],
225
            [ClassResourceConverter::class, 'getClassResourceConverter'],
226
            [OpenApiSpecGenerator::class, 'getOpenApiSpecGenerator'],
227
            [ResourceSerializerInterface::class, 'getResourceSerializer']
228
        ];
229
        while ($item = array_pop($todo)) {
230
            $this->registerApieService($item[0], $item[1]);
231
        }
232
    }
233
234
    private function registerApieService(string $serviceName, string $methodName)
235
    {
236
        $this->app->bind($serviceName, function () use ($methodName) {
237
            return $this->app->get(Apie::class)->$methodName();
238
        });
239
    }
240
241
    private function addStatusResourceServices()
242
    {
243
        $this->app->singleton(StatusFromDatabaseRetriever::class, function () {
244
            return new StatusFromDatabaseRetriever(config('app.debug'));
245
        });
246
        $this->app->tag([StatusFromDatabaseRetriever::class], ['status-check']);
247
        $this->app->singleton(StatusCheckRetriever::class, function () {
248
            return new StatusCheckRetriever($this->app->tagged('status-check'));
249
        });
250
    }
251
}
252