Passed
Push — master ( 0d69f0...90ddb2 )
by Daniel
05:49
created

setUserClassArguments()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 10
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 16
ccs 11
cts 11
cp 1
crap 1
rs 9.9332
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