Test Failed
Pull Request — main (#139)
by Daniel
16:46
created

SilverbackApiComponentsExtension::load()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 86
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 56
CRAP Score 5.0032

Importance

Changes 0
Metric Value
cc 5
eloc 60
c 0
b 0
f 0
nc 16
nop 2
dl 0
loc 86
ccs 56
cts 59
cp 0.9492
crap 5.0032
rs 8.5616

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Silverback API Components Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentsBundle\DependencyInjection;
15
16
use Exception;
17
use Ramsey\Uuid\Doctrine\UuidType;
18
use Silverback\ApiComponentsBundle\AttributeReader\UploadableAttributeReader;
19
use Silverback\ApiComponentsBundle\Doctrine\Extension\ORM\RoutableExtension;
20
use Silverback\ApiComponentsBundle\Doctrine\Extension\ORM\RouteExtension;
21
use Silverback\ApiComponentsBundle\Doctrine\Extension\ORM\TablePrefixExtension;
22
use Silverback\ApiComponentsBundle\Exception\ApiPlatformAuthenticationException;
23
use Silverback\ApiComponentsBundle\Exception\UnparseableRequestHeaderException;
24
use Silverback\ApiComponentsBundle\Exception\UserDisabledException;
25
use Silverback\ApiComponentsBundle\Factory\Uploadable\MediaObjectFactory;
26
use Silverback\ApiComponentsBundle\Factory\User\Mailer\ChangeEmailConfirmationEmailFactory;
27
use Silverback\ApiComponentsBundle\Factory\User\Mailer\PasswordChangedEmailFactory;
28
use Silverback\ApiComponentsBundle\Factory\User\Mailer\PasswordResetEmailFactory;
29
use Silverback\ApiComponentsBundle\Factory\User\Mailer\UserEnabledEmailFactory;
30
use Silverback\ApiComponentsBundle\Factory\User\Mailer\UsernameChangedEmailFactory;
31
use Silverback\ApiComponentsBundle\Factory\User\Mailer\VerifyEmailFactory;
32
use Silverback\ApiComponentsBundle\Factory\User\Mailer\WelcomeEmailFactory;
33
use Silverback\ApiComponentsBundle\Factory\User\UserFactory;
34
use Silverback\ApiComponentsBundle\Form\FormTypeInterface;
35
use Silverback\ApiComponentsBundle\Form\Type\User\ChangePasswordType;
36
use Silverback\ApiComponentsBundle\Form\Type\User\NewEmailAddressType;
37
use Silverback\ApiComponentsBundle\Form\Type\User\PasswordUpdateType;
38
use Silverback\ApiComponentsBundle\Form\Type\User\UserRegisterType;
39
use Silverback\ApiComponentsBundle\Helper\Publishable\PublishableStatusChecker;
40
use Silverback\ApiComponentsBundle\Helper\Uploadable\UploadableFileManager;
41
use Silverback\ApiComponentsBundle\Helper\User\UserDataProcessor;
42
use Silverback\ApiComponentsBundle\Helper\User\UserMailer;
43
use Silverback\ApiComponentsBundle\Repository\Core\RefreshTokenRepository;
44
use Silverback\ApiComponentsBundle\Repository\User\UserRepositoryInterface;
45
use Silverback\ApiComponentsBundle\Security\UserChecker;
46
use Silverback\ApiComponentsBundle\Security\Voter\RoutableVoter;
47
use Silverback\ApiComponentsBundle\Security\Voter\RouteVoter;
48
use Silverback\ApiComponentsBundle\Serializer\Normalizer\MetadataNormalizer;
49
use Symfony\Component\Config\FileLocator;
50
use Symfony\Component\DependencyInjection\ContainerBuilder;
51
use Symfony\Component\DependencyInjection\Extension\Extension;
52
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
53
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
54
use Symfony\Component\DependencyInjection\Reference;
55
use Symfony\Component\Security\Http\Event\LogoutEvent;
56
57
/**
58
 * @author Daniel West <[email protected]>
59
 */
60
class SilverbackApiComponentsExtension extends Extension implements PrependExtensionInterface
61
{
62
    /**
63
     * @throws Exception
64
     */
65 1
    public function load(array $configs, ContainerBuilder $container): void
66
    {
67 1
        $configuration = new Configuration();
68 1
        $config = $this->processConfiguration($configuration, $configs);
69
70 1
        $this->loadServiceConfig($container);
71
72 1
        $definition = $container->getDefinition(TablePrefixExtension::class);
73 1
        $definition->setArgument('$prefix', $config['table_prefix']);
74
75 1
        $definition = $container->getDefinition(UserRepositoryInterface::class);
76 1
        $definition->setArgument('$entityClass', $config['user']['class_name']);
77 1
        $definition->setArgument('$passwordRequestTimeout', $config['user']['password_reset']['request_timeout_seconds']);
78 1
        $definition->setArgument('$newEmailConfirmTimeout', $config['user']['new_email_confirmation']['request_timeout_seconds']);
79
80 1
        $cookieProvider = new Reference('lexik_jwt_authentication.cookie_provider.' . $config['refresh_token']['cookie_name']);
81 1
        $definition = $container->getDefinition('silverback.security.jwt_event_listener');
82 1
        $definition->setArgument('$cookieProvider', $cookieProvider);
83 1
        $container->setParameter('silverback.api_components.refresh_token.ttl', (int) $config['refresh_token']['ttl']);
84
85 1
        if (!empty($config['refresh_token']['options'])) {
86 1
            $definition = $container->getDefinition($config['refresh_token']['handler_id']);
87 1
            $definition->setArgument('$options', $config['refresh_token']['options']);
88
        }
89
90 1
        if ('silverback.api_components.refresh_token.storage.doctrine' === $config['refresh_token']['handler_id']) {
91
            $container
92 1
                ->register(RefreshTokenRepository::class)
93 1
                ->setArguments([new Reference('doctrine'), $config['refresh_token']['options']['class']])
94 1
                ->addTag('doctrine.repository_service');
95
        }
96
97 1
        $definition = $container->getDefinition('silverback.command.refresh_tokens_expire');
98 1
        $definition->setArgument('$storage', new Reference($config['refresh_token']['handler_id']));
99
100 1
        if (class_exists(LogoutEvent::class)) {
101 1
            $definition = $container->getDefinition('silverback.security.logout_listener');
102 1
            $definition->setArgument('$storage', new Reference($config['refresh_token']['handler_id']));
103 1
            $definition->setArgument('$cookieProvider', $cookieProvider);
104
        } else {
105
            $definition = $container->getDefinition('silverback.security.logout_handler');
106
            $definition->setArgument('$storage', new Reference($config['refresh_token']['handler_id']));
107
            $definition->setArgument('$cookieProvider', $cookieProvider);
108
        }
109
110 1
        $definition = $container->getDefinition('silverback.security.jwt_invalid_event_listener');
111 1
        $definition->setArgument('$cookieProvider', $cookieProvider);
112
113 1
        $definition = $container->getDefinition('silverback.security.jwt_manager');
114 1
        $definition->setArgument('$userProvider', new Reference(sprintf('security.user.provider.concrete.%s', $config['refresh_token']['database_user_provider'])));
115 1
        $definition->setArgument('$storage', new Reference($config['refresh_token']['handler_id']));
116
117 1
        $definition = $container->getDefinition(PublishableStatusChecker::class);
118 1
        $definition->setArgument('$permission', $config['publishable']['permission']);
119
120 1
        $definition = $container->getDefinition(MetadataNormalizer::class);
121 1
        $definition->setArgument('$metadataKey', $config['metadata_key']);
122
123 1
        $this->setEmailVerificationArguments($container, $config['user']['email_verification'], $config['user']['password_reset']['repeat_ttl_seconds']);
124 1
        $this->setUserClassArguments($container, $config['user']['class_name']);
125 1
        $this->setMailerServiceArguments($container, $config);
126
127 1
        $imagineEnabled = $container->getParameter('api_components.imagine_enabled');
128 1
        $definition = $container->getDefinition(UploadableAttributeReader::class);
129 1
        $definition->setArgument('$imagineBundleEnabled', $imagineEnabled);
130
131 1
        if ($imagineEnabled) {
132 1
            $definition = $container->getDefinition(UploadableFileManager::class);
133 1
            $definition->setArgument('$filterService', new Reference('liip_imagine.service.filter'));
134 1
            $definition->setArgument('$imagineCacheManager', new Reference('liip_imagine.cache.manager'));
135
136 1
            $definition = $container->getDefinition(MediaObjectFactory::class);
137 1
            $definition->setArgument('$filterService', new Reference('liip_imagine.service.filter'));
138
        }
139
140 1
        $definition = $container->getDefinition(RouteExtension::class);
141 1
        $definition->setArgument('$config', $config['route_security']);
142
143 1
        $definition = $container->getDefinition(RouteVoter::class);
144 1
        $definition->setArgument('$config', $config['route_security']);
145
146 1
        $definition = $container->getDefinition(RoutableExtension::class);
147 1
        $definition->setArgument('$securityStr', $config['routable_security']);
148
149 1
        $definition = $container->getDefinition(RoutableVoter::class);
150 1
        $definition->setArgument('$securityStr', $config['routable_security']);
151
    }
152
153 1
    private function setEmailVerificationArguments(ContainerBuilder $container, array $emailVerificationConfig, int $passwordRepeatTtl): void
154
    {
155 1
        $definition = $container->getDefinition(UserChecker::class);
156 1
        $definition->setArgument('$denyUnverifiedLogin', $emailVerificationConfig['deny_unverified_login']);
157
158 1
        $definition = $container->getDefinition(UserDataProcessor::class);
159 1
        $definition->setArgument('$initialEmailVerifiedState', $emailVerificationConfig['default_value']);
160 1
        $definition->setArgument('$verifyEmailOnRegister', $emailVerificationConfig['verify_on_register']);
161 1
        $definition->setArgument('$verifyEmailOnChange', $emailVerificationConfig['verify_on_change']);
162 1
        $definition->setArgument('$tokenTtl', $passwordRepeatTtl);
163
    }
164
165 1
    private function setUserClassArguments(ContainerBuilder $container, string $userClass): void
166
    {
167 1
        $definition = $container->getDefinition(UserFactory::class);
168 1
        $definition->setArgument('$userClass', $userClass);
169
170 1
        $definition = $container->getDefinition(ChangePasswordType::class);
171 1
        $definition->setArgument('$userClass', $userClass);
172
173 1
        $definition = $container->getDefinition(NewEmailAddressType::class);
174 1
        $definition->setArgument('$userClass', $userClass);
175
176 1
        $definition = $container->getDefinition(UserRegisterType::class);
177 1
        $definition->setArgument('$userClass', $userClass);
178
179 1
        $definition = $container->getDefinition(PasswordUpdateType::class);
180 1
        $definition->setArgument('$userClass', $userClass);
181
    }
182
183 1
    private function setMailerServiceArguments(ContainerBuilder $container, array $config): void
184
    {
185 1
        $definition = $container->getDefinition(UserMailer::class);
186 1
        $definition->setArgument(
187
            '$context',
188
            [
189 1
                'website_name' => $config['website_name'],
190
            ]
191
        );
192
193 1
        $mapping = [
194
            PasswordChangedEmailFactory::class => 'password_changed',
195
            UserEnabledEmailFactory::class => 'user_enabled',
196
            UsernameChangedEmailFactory::class => 'username_changed',
197
            WelcomeEmailFactory::class => 'welcome',
198
        ];
199 1
        foreach ($mapping as $class => $key) {
200 1
            $definition = $container->getDefinition($class);
201 1
            $definition->setArgument('$subject', $config['user']['emails'][$key]['subject']);
202 1
            $definition->setArgument('$enabled', $config['user']['emails'][$key]['enabled']);
203 1
            if (WelcomeEmailFactory::class === $class) {
204 1
                $definition->setArgument('$defaultRedirectPath', $config['user']['email_verification']['email']['default_redirect_path']);
205 1
                $definition->setArgument('$redirectPathQueryKey', $config['user']['email_verification']['email']['redirect_path_query']);
206
            }
207
        }
208
209 1
        $mapping = [
210
            VerifyEmailFactory::class => 'email_verification',
211
            ChangeEmailConfirmationEmailFactory::class => 'new_email_confirmation',
212
            PasswordResetEmailFactory::class => 'password_reset',
213
        ];
214 1
        foreach ($mapping as $class => $key) {
215 1
            $definition = $container->getDefinition($class);
216 1
            $definition->setArgument('$subject', $config['user'][$key]['email']['subject']);
217 1
            $definition->setArgument('$enabled', true);
218 1
            $definition->setArgument('$defaultRedirectPath', $config['user'][$key]['email']['default_redirect_path']);
219 1
            $definition->setArgument('$redirectPathQueryKey', $config['user'][$key]['email']['redirect_path_query']);
220
        }
221
    }
222
223
    /**
224
     * @throws Exception
225
     */
226 1
    private function loadServiceConfig(ContainerBuilder $container): void
227
    {
228 1
        $container->registerForAutoconfiguration(FormTypeInterface::class)
229 1
            ->addTag('silverback_api_components.form_type');
230
231
        $loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
232
        $loader->load('services.php');
233
        $loader->load('services_normalizers.php');
234
235
        // Todo: revert to checking for service id api_platform.http_cache.purger when https://github.com/api-platform/core/pull/4695 is merged
236
        // dump($container->hasDefinition('api_platform.http_cache.purger'));
237
        // if ($container->hasDefinition('api_platform.http_cache.purger.varnish.xkey')) {
238 1
        $loader->load('services_doctrine_orm_http_cache_purger.php');
239 1
        // }
240 1
    }
241
242 1
    public function prepend(ContainerBuilder $container): void
243
    {
244
        $configs = $container->getExtensionConfig($this->getAlias());
245
        $configuration = new Configuration();
246
        $config = $this->processConfiguration($configuration, $configs);
247 1
        $this->prependApiPlatformConfig($container, $config);
248
        $this->prependDoctrineConfiguration($container);
249 1
    }
250 1
251 1
    private function prependDoctrineConfiguration(ContainerBuilder $container): void
252 1
    {
253 1
        $container->prependExtensionConfig(
254
            'doctrine',
255
            [
256 1
                'dbal' => [
257
                    'types' => [
258 1
                        'uuid' => UuidType::class,
259
                    ],
260
                ],
261
            ]
262
        );
263 1
    }
264
265
    private function appendMappingPaths(&$mappingPaths, $srcBase, $name): void
266
    {
267
        $configBasePath = $srcBase . '/Resources/config/api_platform';
268
        $mappingPaths[] = sprintf('%s/%s/resource.xml', $configBasePath, $name);
269
        $propertiesPath = sprintf('%s/%s/properties.xml', $configBasePath, $name);
270 1
        if (file_exists($propertiesPath)) {
271
            $mappingPaths[] = $propertiesPath;
272 1
        }
273 1
    }
274
275 1
    private function prependApiPlatformConfig(ContainerBuilder $container, array $config): void
276 1
    {
277 1
        $srcBase = __DIR__ . '/..';
278 1
        $mappingPaths = [$srcBase . '/Entity/Core'];
279 1
        $this->appendMappingPaths($mappingPaths, $srcBase, 'uploadable');
280 1
        $this->appendMappingPaths($mappingPaths, $srcBase, 'page_data_metadata');
281
        foreach ($config['enabled_components'] as $component => $is_enabled) {
282
            if (true === $is_enabled) {
283
                $this->appendMappingPaths($mappingPaths, $srcBase, $component);
284 1
            }
285
        }
286 1
287
        $websiteName = $config['website_name'];
288
        $container->prependExtensionConfig(
289 1
            'api_platform',
290 1
            [
291
                'title' => $websiteName,
292
                'description' => sprintf('API for %s', $websiteName),
293
                'defaults' => [
294
                    'pagination_client_items_per_page' => true,
295
                    'pagination_maximum_items_per_page' => 100,
296
                ],
297
                'collection' => [
298
                    'pagination' => [
299
                        'items_per_page_parameter_name' => 'perPage',
300
                        // 'client_items_per_page' => true,
301
                        // 'maximum_items_per_page' => 100,
302
                    ],
303 1
                ],
304
                'mapping' => [
305
                    'paths' => $mappingPaths,
306
                ],
307
                'swagger' => [
308
                    'api_keys' => [
309
                        'API Token' => [
310
                            'name' => 'X-AUTH-TOKEN',
311
                            'type' => 'header',
312
                        ],
313
                        'JWT (use prefix `Bearer`)' => [
314
                            'name' => 'Authorization',
315
                            'type' => 'header',
316
                        ],
317
                    ],
318
                ],
319
                'exception_to_status' => [
320
                    UnparseableRequestHeaderException::class => 400,
321
                    ApiPlatformAuthenticationException::class => 401,
322
                    UserDisabledException::class => 401,
323
                ],
324
            ]
325
        );
326
    }
327
}
328