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