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