Completed
Push — master ( 96ea8b...1276b9 )
by Alexis
08:08
created

UserServiceProvider   B

Complexity

Total Complexity 26

Size/Duplication

Total Lines 236
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 18
dl 0
loc 236
rs 7.3333
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
B register() 0 69 6
B boot() 0 23 4
B connect() 0 33 2
B subscribe() 0 26 6
A getOption() 0 8 2
B validateOptions() 0 18 6
1
<?php
2
3
/*
4
 * This file is part of the awurth/silex-user package.
5
 *
6
 * (c) Alexis Wurth <[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
namespace AWurth\Silex\User\Provider;
13
14
use AWurth\Silex\User\Controller\AuthController;
15
use AWurth\Silex\User\Controller\RegistrationController;
16
use AWurth\Silex\User\EventListener\LastLoginListener;
17
use AWurth\Silex\User\Model\UserManager;
18
use AWurth\Silex\User\EventListener\AuthenticationListener;
19
use AWurth\Silex\User\EventListener\EmailConfirmationListener;
20
use AWurth\Silex\User\EventListener\FlashListener;
21
use AWurth\Silex\User\Mailer\TwigSwiftMailer;
22
use AWurth\Silex\User\Security\LoginManager;
23
use AWurth\Silex\User\Util\UserManipulator;
24
use LogicException;
25
use Pimple\Container;
26
use Pimple\ServiceProviderInterface;
27
use Silex\Api\BootableProviderInterface;
28
use Silex\Api\ControllerProviderInterface;
29
use Silex\Api\EventListenerProviderInterface;
30
use Silex\Application;
31
use Silex\ControllerCollection;
32
use Silex\ServiceControllerResolver;
33
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
34
use Symfony\Component\Translation\Loader\PhpFileLoader;
35
use Symfony\Component\Translation\Translator;
36
37
/**
38
 * User Service Provider.
39
 *
40
 * @author Alexis Wurth <[email protected]>
41
 */
42
class UserServiceProvider implements ServiceProviderInterface, BootableProviderInterface, ControllerProviderInterface, EventListenerProviderInterface
43
{
44
    /**
45
     * @var array
46
     */
47
    protected static $defaultOptions = [
48
        'use_routes' => true,
49
        'use_templates' => true,
50
        'use_translations' => true,
51
        'use_flash_notifications' => true,
52
        'use_last_login_listener' => true,
53
        'use_authentication_listener' => false,
54
        'registration.confirmation.enabled' => false,
55
        'registration.confirmation.from_email' => ''
56
    ];
57
58
    /**
59
     * @var array
60
     */
61
    protected static $dependencies = [
62
        'twig' => 'TwigServiceProvider',
63
        'session' => 'SessionServiceProvider',
64
        'translator' => 'TranslationServiceProvider',
65
        'validator' => 'ValidatorServiceProvider',
66
        'form.factory' => 'FormServiceProvider',
67
        'security.token_storage' => 'SecurityServiceProvider'
68
    ];
69
70
    /**
71
     * {@inheritdoc}
72
     */
73
    public function register(Container $app)
74
    {
75
        if (!$app['resolver'] instanceof ServiceControllerResolver) {
76
            throw new LogicException('You must register the ServiceControllerServiceProvider to use the UserServiceProvider');
77
        }
78
79
        foreach (self::$dependencies as $key => $provider) {
80
            if (!isset($app[$key])) {
81
                throw new LogicException('You must register the ' . $provider . ' to use the UserServiceProvider');
82
            }
83
        }
84
85
        $app['silex_user.options'] = [];
86
87
        // Services
88
        $app['silex_user.user_manager'] = function ($app) {
89
            $this->validateOptions($app);
90
91
            return new UserManager(
92
                $app[$app['silex_user.options']['object_manager']],
93
                $app['security.encoder_factory'],
94
                $app['silex_user.options']['user_class']
95
            );
96
        };
97
98
        $app['silex_user.login_manager'] = function ($app) {
99
            return new LoginManager(
100
                $app['security.token_storage'],
101
                $app['security.user_checker'],
102
                $app['security.session_strategy'],
103
                $app['request_stack']
104
            );
105
        };
106
107
        $app['silex_user.user_provider.username'] = function ($app) {
108
            return new UserProvider($app['silex_user.user_manager']);
109
        };
110
111
        $app['silex_user.user_provider.username_email'] = function ($app) {
112
            return new EmailUserProvider($app['silex_user.user_manager']);
113
        };
114
115
        $app['silex_user.mailer'] = function ($app) {
116
            if (isset($app['mailer']) && get_class($app['mailer']) === 'Swift_Mailer') {
117
                $parameters = [
118
                    'from_email' => [
119
                        'confirmation' => $this->getOption($app, 'registration.confirmation.from_email')
120
                    ]
121
                ];
122
123
                return new TwigSwiftMailer($app['mailer'], $app['twig'], $app['url_generator'], $parameters);
124
            }
125
126
            return null;
127
        };
128
129
        $app['silex_user.util.user_manipulator'] = function ($app) {
130
            return new UserManipulator($app['silex_user.user_manager'], $app['dispatcher'], $app['request_stack']);
131
        };
132
133
        // Controllers
134
        $app['silex_user.auth.controller'] = function ($app) {
135
            return new AuthController($app);
136
        };
137
138
        $app['silex_user.registration.controller'] = function ($app) {
139
            return new RegistrationController($app);
140
        };
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function boot(Application $app)
147
    {
148
        if (true === $this->getOption($app, 'use_templates')) {
149
            $app['twig.loader.filesystem']->addPath(dirname(__DIR__) . '/Resources/views/');
150
        }
151
152
        if (true === $this->getOption($app, 'use_translations')) {
153
            /** @var Translator $translator */
154
            $translator = $app['translator'];
155
            $translationsDir = dirname(__DIR__) . '/Resources/translations';
156
157
            $translator->addLoader('php', new PhpFileLoader());
158
159
            $translator->addResource('php', $translationsDir . '/silex_user.en.php', 'en', 'silex_user');
160
            $translator->addResource('php', $translationsDir . '/silex_user.fr.php', 'fr', 'silex_user');
161
            $translator->addResource('php', $translationsDir . '/validators.en.php', 'en', 'validators');
162
            $translator->addResource('php', $translationsDir . '/validators.fr.php', 'fr', 'validators');
163
        }
164
165
        if (true === $this->getOption($app, 'use_routes')) {
166
            $app->mount('/', $this->connect($app));
0 ignored issues
show
Documentation introduced by
$this->connect($app) is of type object<Silex\ControllerCollection>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
167
        }
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173
    public function connect(Application $app)
174
    {
175
        /** @var ControllerCollection $controllers */
176
        $controllers = $app['controllers_factory'];
177
178
        $controllers->get('/login', 'silex_user.auth.controller:loginAction')
179
            ->bind('silex_user.login');
180
181
        $controllers->method('GET|POST')
182
            ->match('/login_check')
183
            ->bind('silex_user.login_check');
184
185
        $controllers->method('GET|POST')
186
            ->match('/logout')
187
            ->bind('silex_user.logout');
188
189
        $controllers->method('GET|POST')
190
            ->match('/register', 'silex_user.registration.controller:registerAction')
191
            ->bind('silex_user.register');
192
193
        $controllers->get('/register/confirmed', 'silex_user.registration.controller:confirmedAction')
194
            ->bind('silex_user.registration_confirmed');
195
196
        if (true === $this->getOption($app, 'registration.confirmation.enabled')) {
197
            $controllers->get('/register/check-email', 'silex_user.registration.controller:checkEmailAction')
198
                ->bind('silex_user.registration_check_email');
199
200
            $controllers->get('/register/confirm/{token}', 'silex_user.registration.controller:confirmAction')
201
                ->bind('silex_user.registration_confirm');
202
        }
203
204
        return $controllers;
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210
    public function subscribe(Container $app, EventDispatcherInterface $dispatcher)
211
    {
212
        $app['silex_user.options'] = array_replace(self::$defaultOptions, $app['silex_user.options']);
213
214
        $this->validateOptions($app);
0 ignored issues
show
Compatibility introduced by
$app of type object<Pimple\Container> is not a sub-type of object<Silex\Application>. It seems like you assume a child class of the class Pimple\Container to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
215
216
        if (true === $this->getOption($app, 'use_last_login_listener')) {
217
            $dispatcher->addSubscriber(new LastLoginListener($app['silex_user.user_manager']));
218
        }
219
220
        if (true === $this->getOption($app, 'use_authentication_listener')) {
221
            $dispatcher->addSubscriber(new AuthenticationListener($app['silex_user.login_manager'], $app['silex_user.options']['firewall_name']));
222
        }
223
224
        if (true === $this->getOption($app, 'use_flash_notifications')) {
225
            $dispatcher->addSubscriber(new FlashListener($app['session'], $app['translator']));
226
        }
227
228
        if (true === $this->getOption($app, 'registration.confirmation.enabled')) {
229
            if (null === $app['silex_user.mailer']) {
230
                throw new LogicException('You must configure a mailer to enable email notifications');
231
            }
232
233
            $dispatcher->addSubscriber(new EmailConfirmationListener($app['silex_user.mailer'], $app['url_generator'], $app['session']));
234
        }
235
    }
236
237
    /**
238
     * Gets an option or its default value if it is not set.
239
     *
240
     * @param Container $app
241
     * @param string $name
242
     *
243
     * @return mixed
244
     */
245
    protected function getOption(Container $app, $name)
246
    {
247
        if (isset($app['silex_user.options'][$name])) {
248
            return $app['silex_user.options'][$name];
249
        } else {
250
            return self::$defaultOptions[$name];
251
        }
252
    }
253
254
    /**
255
     * Checks if options are set correctly.
256
     *
257
     * @param Application $app
258
     */
259
    protected function validateOptions(Application $app)
260
    {
261
        if (empty($app['silex_user.options']['object_manager'])) {
262
            throw new LogicException('The "object_manager" option must be set');
263
        }
264
265
        if (empty($app['silex_user.options']['user_class'])) {
266
            throw new LogicException('The "user_class" option must be set');
267
        }
268
269
        if (empty($app['silex_user.options']['firewall_name'])) {
270
            throw new LogicException('The "firewall_name" option must be set');
271
        }
272
273
        if (true === $this->getOption($app, 'registration.confirmation.enabled') && empty($this->getOption($app, 'registration.confirmation.from_email'))) {
274
            throw new LogicException('The "registration.confirmation.from_email" option must be set');
275
        }
276
    }
277
}
278