AuthChoice   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 70
dl 0
loc 211
ccs 0
cts 67
cp 0
rs 10
c 2
b 0
f 0
wmc 23

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A init() 0 18 3
A getId() 0 3 1
A setClients() 0 3 1
B clientLink() 0 41 10
A authRoute() 0 4 1
A render() 0 8 2
A getClients() 0 3 1
A createClientUrl() 0 7 1
A renderMainContent() 0 8 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\AuthClient\Widget;
6
7
use Yiisoft\Assets\AssetManager;
8
use Yiisoft\Html\Html;
9
use Yiisoft\Json\Json;
10
use Yiisoft\Router\UrlGeneratorInterface;
11
use Yiisoft\View\WebView;
12
use Yiisoft\Widget\Widget;
13
use Yiisoft\Yii\AuthClient\Asset\AuthChoiceAsset;
14
use Yiisoft\Yii\AuthClient\Asset\AuthChoiceStyleAsset;
15
use Yiisoft\Yii\AuthClient\AuthClientInterface;
16
use Yiisoft\Yii\AuthClient\Collection;
17
use Yiisoft\Yii\AuthClient\Exception\InvalidConfigException;
18
19
/**
20
 * AuthChoice prints buttons for authentication via various auth clients.
21
 * It opens a popup window for the client authentication process.
22
 * By default this widget relies on presence of {@see \Yiisoft\Yii\AuthClient\Collection} among application components
23
 * to get auth clients information.
24
 *
25
 * Example:
26
 *
27
 * ```php
28
 * <?= AuthChoice::widget()->authRoute('site/auth'); ?>
29
 * ```
30
 *
31
 * You can customize the widget appearance by using {@see begin()} and {@see end()} syntax
32
 * along with using method {@see clientLink()} or {@see createClientUrl()}.
33
 * For example:
34
 *
35
 * ```php
36
 * <?php
37
 * use Yiisoft\Yii\AuthClient\Widget\AuthChoice;
38
 * ?>
39
 * <?php $authChoice = AuthChoice::begin([
40
 *     'baseAuthUrl' => ['site/auth']
41
 * ]); ?>
42
 * <ul>
43
 * <?php foreach ($authChoice->getClients() as $client): ?>
44
 *     <li><?= $authChoice->clientLink($client) ?></li>
45
 * <?php endforeach; ?>
46
 * </ul>
47
 * <?php AuthChoice::end(); ?>
48
 * ```
49
 *
50
 * This widget supports following keys for {@see AuthClientInterface::getViewOptions()} result:
51
 *
52
 *  - popupWidth: int, width of the popup window in pixels.
53
 *  - popupHeight: int, height of the popup window in pixels.
54
 *  - widget: array, configuration for the widget, which should be used to render a client link;
55
 *    such widget should be a subclass of {@see AuthChoiceItem}.
56
 *
57
 * @see \Yiisoft\Yii\AuthClient\AuthAction
58
 */
59
final class AuthChoice extends Widget
60
{
61
    /**
62
     * @var string name of the GET param , which should be used to passed auth client id to URL
63
     * defined by {@see baseAuthUrl}.
64
     */
65
    private string $clientIdGetParamName = 'authclient';
66
    /**
67
     * @var array the HTML attributes that should be rendered in the div HTML tag representing the container element.
68
     *
69
     * @see Html::renderTagAttributes() for details on how attributes are being rendered.
70
     */
71
    private array $options = [];
72
    /**
73
     * @var array additional options to be passed to the underlying JS plugin.
74
     */
75
    private array $clientOptions = [];
76
    /**
77
     * @var bool indicates if popup window should be used instead of direct links.
78
     */
79
    private bool $popupMode = true;
80
    /**
81
     * @var bool indicates if widget content, should be rendered automatically.
82
     * Note: this value automatically set to 'false' at the first call of {@see createClientUrl()}
83
     */
84
    private bool $autoRender = true;
85
86
    /**
87
     * @var string route name for the external clients authentication URL.
88
     */
89
    private string $authRoute;
90
    /**
91
     * @var AuthClientInterface[] auth providers list.
92
     */
93
    private array $clients;
94
    private UrlGeneratorInterface $urlGenerator;
95
    private WebView $webView;
96
    private AssetManager $assetManager;
97
98
    public function __construct(
99
        Collection $clientCollection,
100
        UrlGeneratorInterface $urlGenerator,
101
        WebView $webView,
102
        AssetManager $assetManager
103
    ) {
104
        $this->clients = $clientCollection->getClients();
105
        $this->urlGenerator = $urlGenerator;
106
        $this->webView = $webView;
107
        $this->assetManager = $assetManager;
108
        $this->init();
109
    }
110
111
    /**
112
     * Initializes the widget.
113
     */
114
    public function init(): void
115
    {
116
        if ($this->popupMode) {
117
            $this->assetManager->register(AuthChoiceAsset::class);
118
119
            if (empty($this->clientOptions)) {
120
                $options = '';
121
            } else {
122
                $options = Json::htmlEncode($this->clientOptions);
123
            }
124
125
            $this->webView->registerJs("jQuery('#" . $this->getId() . "').authchoice({$options});");
126
        } else {
127
            $this->assetManager->register(AuthChoiceStyleAsset::class);
128
        }
129
130
        $this->options['id'] = $this->getId();
131
        echo Html::tag('div', '', $this->options)->open();
132
    }
133
134
    public function getId(): string
135
    {
136
        return 'yii-auth-client';
137
    }
138
139
    /**
140
     * Runs the widget.
141
     *
142
     * @throws \Yiisoft\Definitions\Exception\InvalidConfigException
143
     *
144
     * @return string rendered HTML.
145
     */
146
    public function render(): string
147
    {
148
        $content = '';
149
        if ($this->autoRender) {
150
            $content .= $this->renderMainContent();
151
        }
152
        $content .= Html::tag('div')->close();
153
        return $content;
154
    }
155
156
    /**
157
     * Renders the main content, which includes all external services links.
158
     *
159
     * @throws InvalidConfigException
160
     * @throws \Yiisoft\Definitions\Exception\InvalidConfigException
161
     *
162
     * @return string generated HTML.
163
     */
164
    protected function renderMainContent(): string
165
    {
166
        $items = [];
167
        foreach ($this->getClients() as $externalService) {
168
            $items[] = Html::tag('li', $this->clientLink($externalService));
169
        }
170
171
        return Html::tag('ul', implode('', $items), ['class' => 'auth-clients'])->render();
172
    }
173
174
    /**
175
     * @return AuthClientInterface[] auth providers
176
     */
177
    public function getClients(): array
178
    {
179
        return $this->clients;
180
    }
181
182
    /**
183
     * @param AuthClientInterface[] $clients auth providers
184
     */
185
    public function setClients(array $clients): void
186
    {
187
        $this->clients = $clients;
188
    }
189
190
    /**
191
     * Outputs client auth link.
192
     *
193
     * @param AuthClientInterface $client external auth client instance.
194
     * @param string $text link text, if not set - default value will be generated.
195
     * @param array $htmlOptions link HTML options.
196
     *
197
     * @throws InvalidConfigException on wrong configuration.
198
     * @throws \Yiisoft\Definitions\Exception\InvalidConfigException
199
     *
200
     * @return string generated HTML.
201
     */
202
    public function clientLink(AuthClientInterface $client, string $text = null, array $htmlOptions = []): string
203
    {
204
        $viewOptions = $client->getViewOptions();
205
206
        if (empty($viewOptions['widget'])) {
207
            if ($text === null) {
208
                $text = Html::tag('span', '', ['class' => 'auth-icon ' . $client->getName()])->render();
209
            }
210
            if (!isset($htmlOptions['class'])) {
211
                $htmlOptions['class'] = $client->getName();
212
            }
213
            if (!isset($htmlOptions['title'])) {
214
                $htmlOptions['title'] = $client->getTitle();
215
            }
216
            Html::addCssClass($htmlOptions, ['widget' => 'auth-link']);
217
218
            if ($this->popupMode) {
219
                if (isset($viewOptions['popupWidth'])) {
220
                    $htmlOptions['data-popup-width'] = $viewOptions['popupWidth'];
221
                }
222
                if (isset($viewOptions['popupHeight'])) {
223
                    $htmlOptions['data-popup-height'] = $viewOptions['popupHeight'];
224
                }
225
            }
226
227
            return Html::a($text, $this->createClientUrl($client), $htmlOptions)->render();
228
        }
229
230
        $widgetConfig = $viewOptions['widget'];
231
        if (!isset($widgetConfig['class'])) {
232
            throw new InvalidConfigException('Widget config "class" parameter is missing');
233
        }
234
        /* @var $widgetClass Widget */
235
        $widgetClass = $widgetConfig['class'];
236
        if (!is_subclass_of($widgetClass, AuthChoiceItem::class)) {
237
            throw new InvalidConfigException('Item widget class must be subclass of "' . AuthChoiceItem::class . '"');
238
        }
239
        unset($widgetConfig['class']);
240
        $widgetConfig['client'] = $client;
241
        $widgetConfig['authChoice'] = $this;
242
        return $widgetClass::widget($widgetConfig)->render();
243
    }
244
245
    /**
246
     * Composes client auth URL.
247
     *
248
     * @param AuthClientInterface $client external auth client instance.
249
     *
250
     * @return string auth URL.
251
     */
252
    public function createClientUrl($client): string
253
    {
254
        $this->autoRender = false;
255
        $params = [];
256
        $params[$this->clientIdGetParamName] = $client->getName();
257
258
        return $this->urlGenerator->generate($this->authRoute, $params);
259
    }
260
261
    /**
262
     * @param string $authRoute
263
     *
264
     * @return self
265
     */
266
    public function authRoute(string $authRoute): self
267
    {
268
        $this->authRoute = $authRoute;
269
        return $this;
270
    }
271
}
272