Completed
Push — 1.4-password-hashing-2 ( b79be0 )
by Kamil
16:31
created

SyliusUserExtension::createFactories()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.552
c 0
b 0
f 0
cc 3
nc 3
nop 3

1 Method

Rating   Name   Duplication   Size   Complexity  
A SyliusUserExtension::loadEncodersAwareServices() 0 13 3
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
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 Sylius\Bundle\UserBundle\DependencyInjection;
15
16
use Sylius\Bundle\ResourceBundle\DependencyInjection\Extension\AbstractResourceExtension;
17
use Sylius\Bundle\UserBundle\EventListener\UpdateUserEncoderListener;
18
use Sylius\Bundle\UserBundle\EventListener\UserDeleteListener;
19
use Sylius\Bundle\UserBundle\EventListener\UserLastLoginSubscriber;
20
use Sylius\Bundle\UserBundle\EventListener\UserReloaderListener;
21
use Sylius\Bundle\UserBundle\Factory\UserWithEncoderFactory;
22
use Sylius\Bundle\UserBundle\Provider\AbstractUserProvider;
23
use Sylius\Bundle\UserBundle\Provider\EmailProvider;
24
use Sylius\Bundle\UserBundle\Provider\UsernameOrEmailProvider;
25
use Sylius\Bundle\UserBundle\Provider\UsernameProvider;
26
use Sylius\Bundle\UserBundle\Reloader\UserReloader;
27
use Sylius\Component\User\Security\Checker\TokenUniquenessChecker;
28
use Sylius\Component\User\Security\Generator\UniquePinGenerator;
29
use Sylius\Component\User\Security\Generator\UniqueTokenGenerator;
30
use Symfony\Component\Config\FileLocator;
31
use Symfony\Component\DependencyInjection\ChildDefinition;
32
use Symfony\Component\DependencyInjection\ContainerBuilder;
33
use Symfony\Component\DependencyInjection\Definition;
34
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
35
use Symfony\Component\DependencyInjection\Reference;
36
use Symfony\Component\Security\Http\SecurityEvents;
37
38
final class SyliusUserExtension extends AbstractResourceExtension
39
{
40
    /**
41
     * {@inheritdoc}
42
     */
43
    public function load(array $config, ContainerBuilder $container): void
44
    {
45
        $config = $this->processConfiguration($this->getConfiguration([], $container), $config);
46
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
47
48
        $loader->load(sprintf('services/integrations/%s.xml', $config['driver']));
49
50
        $this->registerResources('sylius', $config['driver'], $this->resolveResources($config['resources'], $container), $container);
51
52
        $loader->load('services.xml');
53
54
        $this->createServices($config['resources'], $container);
55
        $this->loadEncodersAwareServices($config['encoder'], $config['resources'], $container);
56
    }
57
58
    private function resolveResources(array $resources, ContainerBuilder $container): array
59
    {
60
        $container->setParameter('sylius.user.users', $resources);
61
62
        $resolvedResources = [];
63
        foreach ($resources as $variableName => $variableConfig) {
64
            foreach ($variableConfig as $resourceName => $resourceConfig) {
65
                if (is_array($resourceConfig)) {
66
                    $resolvedResources[$variableName . '_' . $resourceName] = $resourceConfig;
67
                }
68
            }
69
        }
70
71
        return $resolvedResources;
72
    }
73
74
    private function createServices(array $resources, ContainerBuilder $container): void
75
    {
76
        foreach ($resources as $userType => $config) {
77
            $userClass = $config['user']['classes']['model'];
78
79
            $this->createTokenGenerators($userType, $config['user'], $container);
80
            $this->createReloaders($userType, $container);
81
            $this->createLastLoginListeners($userType, $userClass, $container);
82
            $this->createProviders($userType, $userClass, $container);
83
            $this->createUserDeleteListeners($userType, $container);
84
        }
85
    }
86
87
    private function loadEncodersAwareServices(?string $globalEncoder, array $resources, ContainerBuilder $container): void
88
    {
89
        foreach ($resources as $userType => $config) {
90
            $encoder = $config['user']['encoder'] ?? $globalEncoder;
91
92
            if (null === $encoder) {
93
                continue;
94
            }
95
96
            $this->overwriteResourceFactoryWithEncoderAwareFactory($container, $userType, $encoder);
97
            $this->registerUpdateUserEncoderListener($container, $userType, $encoder, $config);
98
        }
99
    }
100
101
    private function createTokenGenerators(string $userType, array $config, ContainerBuilder $container): void
102
    {
103
        $this->createUniquenessCheckers($userType, $config, $container);
104
105
        $container->setDefinition(
106
            sprintf('sylius.%s_user.token_generator.password_reset', $userType),
107
            $this->createTokenGeneratorDefinition(
108
                UniqueTokenGenerator::class,
109
                [
110
                    new Reference('sylius.random_generator'),
111
                    new Reference(sprintf('sylius.%s_user.token_uniqueness_checker.password_reset', $userType)),
112
                    $config['resetting']['token']['length'],
113
                ]
114
            )
115
        )->setPublic(true);
116
117
        $container->setDefinition(
118
            sprintf('sylius.%s_user.pin_generator.password_reset', $userType),
119
            $this->createTokenGeneratorDefinition(
120
                UniquePinGenerator::class,
121
                [
122
                    new Reference('sylius.random_generator'),
123
                    new Reference(sprintf('sylius.%s_user.pin_uniqueness_checker.password_reset', $userType)),
124
                    $config['resetting']['pin']['length'],
125
                ]
126
            )
127
        )->setPublic(true);
128
129
        $container->setDefinition(
130
            sprintf('sylius.%s_user.token_generator.email_verification', $userType),
131
            $this->createTokenGeneratorDefinition(
132
                UniqueTokenGenerator::class,
133
                [
134
                    new Reference('sylius.random_generator'),
135
                    new Reference(sprintf('sylius.%s_user.token_uniqueness_checker.email_verification', $userType)),
136
                    $config['verification']['token']['length'],
137
                ]
138
            )
139
        )->setPublic(true);
140
    }
141
142
    private function createTokenGeneratorDefinition(string $generatorClass, array $arguments): Definition
143
    {
144
        $generatorDefinition = new Definition($generatorClass);
145
        $generatorDefinition->setArguments($arguments);
146
147
        return $generatorDefinition;
148
    }
149
150
    private function createUniquenessCheckers(string $userType, array $config, ContainerBuilder $container): void
151
    {
152
        $repositoryServiceId = sprintf('sylius.repository.%s_user', $userType);
153
154
        $resetPasswordTokenUniquenessCheckerDefinition = new Definition(TokenUniquenessChecker::class);
155
        $resetPasswordTokenUniquenessCheckerDefinition->addArgument(new Reference($repositoryServiceId));
156
        $resetPasswordTokenUniquenessCheckerDefinition->addArgument($config['resetting']['token']['field_name']);
157
        $container->setDefinition(
158
            sprintf('sylius.%s_user.token_uniqueness_checker.password_reset', $userType),
159
            $resetPasswordTokenUniquenessCheckerDefinition
160
        );
161
162
        $resetPasswordPinUniquenessCheckerDefinition = new Definition(TokenUniquenessChecker::class);
163
        $resetPasswordPinUniquenessCheckerDefinition->addArgument(new Reference($repositoryServiceId));
164
        $resetPasswordPinUniquenessCheckerDefinition->addArgument($config['resetting']['pin']['field_name']);
165
        $container->setDefinition(
166
            sprintf('sylius.%s_user.pin_uniqueness_checker.password_reset', $userType),
167
            $resetPasswordPinUniquenessCheckerDefinition
168
        );
169
170
        $emailVerificationTokenUniquenessCheckerDefinition = new Definition(TokenUniquenessChecker::class);
171
        $emailVerificationTokenUniquenessCheckerDefinition->addArgument(new Reference($repositoryServiceId));
172
        $emailVerificationTokenUniquenessCheckerDefinition->addArgument($config['verification']['token']['field_name']);
173
        $container->setDefinition(
174
            sprintf('sylius.%s_user.token_uniqueness_checker.email_verification', $userType),
175
            $emailVerificationTokenUniquenessCheckerDefinition
176
        );
177
    }
178
179
    private function createReloaders(string $userType, ContainerBuilder $container): void
180
    {
181
        $managerServiceId = sprintf('sylius.manager.%s_user', $userType);
182
        $reloaderServiceId = sprintf('sylius.%s_user.reloader', $userType);
183
        $reloaderListenerServiceId = sprintf('sylius.listener.%s_user.reloader', $userType);
184
185
        $userReloaderDefinition = new Definition(UserReloader::class);
186
        $userReloaderDefinition->addArgument(new Reference($managerServiceId));
187
        $container->setDefinition($reloaderServiceId, $userReloaderDefinition);
188
189
        $userReloaderListenerDefinition = new Definition(UserReloaderListener::class);
190
        $userReloaderListenerDefinition->addArgument(new Reference($reloaderServiceId));
191
        $userReloaderListenerDefinition->addTag('kernel.event_listener', ['event' => sprintf('sylius.%s_user.post_create', $userType), 'method' => 'reloadUser']);
192
        $userReloaderListenerDefinition->addTag('kernel.event_listener', ['event' => sprintf('sylius.%s_user.post_update', $userType), 'method' => 'reloadUser']);
193
        $container->setDefinition($reloaderListenerServiceId, $userReloaderListenerDefinition);
194
    }
195
196
    private function createLastLoginListeners(string $userType, string $userClass, ContainerBuilder $container): void
197
    {
198
        $managerServiceId = sprintf('sylius.manager.%s_user', $userType);
199
        $lastLoginListenerServiceId = sprintf('sylius.listener.%s_user_last_login', $userType);
200
201
        $lastLoginListenerDefinition = new Definition(UserLastLoginSubscriber::class);
202
        $lastLoginListenerDefinition->setArguments([new Reference($managerServiceId), $userClass]);
203
        $lastLoginListenerDefinition->addTag('kernel.event_subscriber');
204
        $container->setDefinition($lastLoginListenerServiceId, $lastLoginListenerDefinition);
205
    }
206
207
    public function createUserDeleteListeners(string $userType, ContainerBuilder $container): void
208
    {
209
        $userDeleteListenerServiceId = sprintf('sylius.listener.%s_user_delete', $userType);
210
        $userPreDeleteEventName = sprintf('sylius.%s_user.pre_delete', $userType);
211
212
        $userDeleteListenerDefinition = new Definition(UserDeleteListener::class);
213
        $userDeleteListenerDefinition->addArgument(new Reference('security.token_storage'));
214
        $userDeleteListenerDefinition->addArgument(new Reference('session'));
215
        $userDeleteListenerDefinition->addTag('kernel.event_listener', ['event' => $userPreDeleteEventName, 'method' => 'deleteUser']);
216
        $container->setDefinition($userDeleteListenerServiceId, $userDeleteListenerDefinition);
217
    }
218
219
    private function createProviders(string $userType, string $userModel, ContainerBuilder $container): void
220
    {
221
        $repositoryServiceId = sprintf('sylius.repository.%s_user', $userType);
222
        $abstractProviderServiceId = sprintf('sylius.%s_user_provider', $userType);
223
        $providerEmailBasedServiceId = sprintf('sylius.%s_user_provider.email_based', $userType);
224
        $providerNameBasedServiceId = sprintf('sylius.%s_user_provider.name_based', $userType);
225
        $providerEmailOrNameBasedServiceId = sprintf('sylius.%s_user_provider.email_or_name_based', $userType);
226
227
        $abstractProviderDefinition = new Definition(AbstractUserProvider::class);
228
        $abstractProviderDefinition->setAbstract(true);
229
        $abstractProviderDefinition->setLazy(true);
230
        $abstractProviderDefinition->addArgument($userModel);
231
        $abstractProviderDefinition->addArgument(new Reference($repositoryServiceId));
232
        $abstractProviderDefinition->addArgument(new Reference('sylius.canonicalizer'));
233
        $container->setDefinition($abstractProviderServiceId, $abstractProviderDefinition);
234
235
        $emailBasedProviderDefinition = new ChildDefinition($abstractProviderServiceId);
236
        $emailBasedProviderDefinition->setClass(EmailProvider::class);
237
        $container->setDefinition($providerEmailBasedServiceId, $emailBasedProviderDefinition);
238
239
        $nameBasedProviderDefinition = new ChildDefinition($abstractProviderServiceId);
240
        $nameBasedProviderDefinition->setClass(UsernameProvider::class);
241
        $container->setDefinition($providerNameBasedServiceId, $nameBasedProviderDefinition);
242
243
        $emailOrNameBasedProviderDefinition = new ChildDefinition($abstractProviderServiceId);
244
        $emailOrNameBasedProviderDefinition->setClass(UsernameOrEmailProvider::class);
245
        $container->setDefinition($providerEmailOrNameBasedServiceId, $emailOrNameBasedProviderDefinition);
246
    }
247
248
    private function overwriteResourceFactoryWithEncoderAwareFactory(ContainerBuilder $container, string $userType, string $encoder): void
249
    {
250
        $factoryServiceId = sprintf('sylius.factory.%s_user', $userType);
251
252
        $factoryDefinition = new Definition(
253
            UserWithEncoderFactory::class,
254
            [
255
                $container->getDefinition($factoryServiceId),
256
                $encoder,
257
            ]
258
        );
259
        $factoryDefinition->setPublic(true);
260
261
        $container->setDefinition($factoryServiceId, $factoryDefinition);
262
    }
263
264
    private function registerUpdateUserEncoderListener(ContainerBuilder $container, string $userType, string $encoder, array $resourceConfig): void
265
    {
266
        $updateUserEncoderListenerDefinition = new Definition(UpdateUserEncoderListener::class, [
267
            new Reference(sprintf('sylius.manager.%s_user', $userType)),
268
            $encoder,
269
            $resourceConfig['user']['classes']['model'],
270
            $resourceConfig['user']['classes']['interface'],
271
            '_password',
272
        ]);
273
        $updateUserEncoderListenerDefinition->addTag('kernel.event_listener', ['event' => SecurityEvents::INTERACTIVE_LOGIN]);
274
275
        $container->setDefinition(
276
            sprintf('sylius.%s_user.listener.update_user_encoder', $userType),
277
            $updateUserEncoderListenerDefinition
278
        );
279
    }
280
}
281