Passed
Push — master ( 13425d...f357db )
by Alexander
02:26
created

AuthChoice::defaultBaseAuthUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 8
ccs 0
cts 5
cp 0
crap 2
rs 10
c 0
b 0
f 0
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;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Html\Html was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Yiisoft\Json\Json;
10
use Yiisoft\Router\UrlGeneratorInterface;
11
use Yiisoft\View\WebView;
0 ignored issues
show
Bug introduced by
The type Yiisoft\View\WebView was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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(
118
                [
119
                    AuthChoiceAsset::class,
120
                ]
121
            );
122
            if (empty($this->clientOptions)) {
123
                $options = '';
124
            } else {
125
                $options = Json::htmlEncode($this->clientOptions);
126
            }
127
            $this->webView->registerJs("jQuery('#" . $this->getId() . "').authchoice({$options});");
128
        } else {
129
            $this->assetManager->register(
130
                [
131
                    AuthChoiceStyleAsset::class,
132
                ]
133
            );
134
        }
135
        $this->options['id'] = $this->getId();
136
        echo Html::beginTag('div', $this->options);
137
    }
138
139
    public function getId(): string
140
    {
141
        return 'yii-auth-client';
142
    }
143
144
    /**
145
     * Runs the widget.
146
     *
147
     * @throws \Yiisoft\Factory\Exceptions\InvalidConfigException
148
     * @return string rendered HTML.
149
     */
150
    public function run(): string
151
    {
152
        $content = '';
153
        if ($this->autoRender) {
154
            $content .= $this->renderMainContent();
155
        }
156
        $content .= Html::endTag('div');
157
        return $content;
158
    }
159
160
    /**
161
     * Renders the main content, which includes all external services links.
162
     *
163
     * @throws InvalidConfigException
164
     * @throws \Yiisoft\Factory\Exceptions\InvalidConfigException
165
     *
166
     * @return string generated HTML.
167
     */
168
    protected function renderMainContent(): string
169
    {
170
        $items = [];
171
        foreach ($this->getClients() as $externalService) {
172
            $items[] = Html::tag('li', $this->clientLink($externalService));
173
        }
174
        return Html::tag('ul', implode('', $items), ['class' => 'auth-clients']);
175
    }
176
177
    /**
178
     * @return AuthClientInterface[] auth providers
179
     */
180
    public function getClients(): array
181
    {
182
        return $this->clients;
183
    }
184
185
    /**
186
     * @param AuthClientInterface[] $clients auth providers
187
     */
188
    public function setClients(array $clients): void
189
    {
190
        $this->clients = $clients;
191
    }
192
193
    /**
194
     * Outputs client auth link.
195
     *
196
     * @param AuthClientInterface $client external auth client instance.
197
     * @param string $text link text, if not set - default value will be generated.
198
     * @param array $htmlOptions link HTML options.
199
     *
200
     * @throws InvalidConfigException on wrong configuration.
201
     * @throws \Yiisoft\Factory\Exceptions\InvalidConfigException
202
     *
203
     * @return string generated HTML.
204
     */
205
    public function clientLink(AuthClientInterface $client, string $text = null, array $htmlOptions = []): string
206
    {
207
        $viewOptions = $client->getViewOptions();
208
209
        if (empty($viewOptions['widget'])) {
210
            if ($text === null) {
211
                $text = Html::tag('span', '', ['class' => 'auth-icon ' . $client->getName()]);
212
            }
213
            if (!isset($htmlOptions['class'])) {
214
                $htmlOptions['class'] = $client->getName();
215
            }
216
            if (!isset($htmlOptions['title'])) {
217
                $htmlOptions['title'] = $client->getTitle();
218
            }
219
            Html::addCssClass($htmlOptions, ['widget' => 'auth-link']);
220
221
            if ($this->popupMode) {
222
                if (isset($viewOptions['popupWidth'])) {
223
                    $htmlOptions['data-popup-width'] = $viewOptions['popupWidth'];
224
                }
225
                if (isset($viewOptions['popupHeight'])) {
226
                    $htmlOptions['data-popup-height'] = $viewOptions['popupHeight'];
227
                }
228
            }
229
            return Html::a($text, $this->createClientUrl($client), $htmlOptions);
230
        }
231
232
        $widgetConfig = $viewOptions['widget'];
233
        if (!isset($widgetConfig['__class'])) {
234
            throw new InvalidConfigException('Widget config "class" parameter is missing');
235
        }
236
        /* @var $widgetClass Widget */
237
        $widgetClass = $widgetConfig['__class'];
238
        if (!(is_subclass_of($widgetClass, AuthChoiceItem::class))) {
239
            throw new InvalidConfigException('Item widget class must be subclass of "' . AuthChoiceItem::class . '"');
240
        }
241
        unset($widgetConfig['__class']);
242
        $widgetConfig['client'] = $client;
243
        $widgetConfig['authChoice'] = $this;
244
        return $widgetClass::widget($widgetConfig)->render();
245
    }
246
247
    /**
248
     * Composes client auth URL.
249
     *
250
     * @param AuthClientInterface $client external auth client instance.
251
     *
252
     * @return string auth URL.
253
     */
254
    public function createClientUrl($client): string
255
    {
256
        $this->autoRender = false;
257
        $params = [];
258
        $params[$this->clientIdGetParamName] = $client->getName();
259
260
        return $this->urlGenerator->generate($this->authRoute, $params);
261
    }
262
263
    /**
264
     * @param string $authRoute
265
     *
266
     * @return self
267
     */
268
    public function authRoute(string $authRoute): self
269
    {
270
        $this->authRoute = $authRoute;
271
        return $this;
272
    }
273
}
274