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