diff --git a/extensions/yii/authclient/provider/Collection.php b/extensions/yii/authclient/provider/Collection.php index 303f109..309eae5 100644 --- a/extensions/yii/authclient/provider/Collection.php +++ b/extensions/yii/authclient/provider/Collection.php @@ -97,7 +97,7 @@ class Collection extends Component * @param array $config auth provider instance configuration. * @return ProviderInterface auth provider instance. */ - protected function createProvider($id, array $config) + protected function createProvider($id, $config) { $config['id'] = $id; return Yii::createObject($config); diff --git a/extensions/yii/authclient/widgets/Choice.php b/extensions/yii/authclient/widgets/Choice.php new file mode 100644 index 0000000..5585529 --- /dev/null +++ b/extensions/yii/authclient/widgets/Choice.php @@ -0,0 +1,198 @@ + + * @since 2.0 + */ +class Choice extends Widget +{ + /** + * @var ProviderInterface[] auth providers list. + */ + protected $_providers; + /** + * @var string name of the auth provider collection application component. + * This component will be used to fetch {@link services} value if it is not set. + */ + public $providerCollection; + /** + * @var array configuration for the external services base authentication URL. + */ + protected $_baseAuthUrl; + /** + * @var string name of the GET param , which should be used to passed auth provider id to URL + * defined by {@link baseAuthUrl}. + */ + public $providerIdGetParamName = 'provider'; + /** + * @var array the HTML attributes that should be rendered in the div HTML tag representing the container element. + */ + public $mainContainerHtmlOptions = [ + 'class' => 'services' + ]; + /** + * @var boolean indicates if popup window should be used instead of direct links. + */ + public $popupMode = true; + /** + * @var boolean indicates if widget content, should be rendered automatically. + * Note: this value automatically set to 'false' at the first call of [[createProviderUrl()]] + */ + public $autoRender = true; + + /** + * @param ProviderInterface[] $providers auth providers + */ + public function setProviders(array $providers) + { + $this->_providers = $providers; + } + + /** + * @return ProviderInterface[] auth providers + */ + public function getProviders() + { + if ($this->_providers === null) { + $this->_providers = $this->defaultProviders(); + } + return $this->_providers; + } + + /** + * @param array $baseAuthUrl base auth URL configuration. + */ + public function setBaseAuthUrl(array $baseAuthUrl) + { + $this->_baseAuthUrl = $baseAuthUrl; + } + + /** + * @return array base auth URL configuration. + */ + public function getBaseAuthUrl() + { + if (!is_array($this->_baseAuthUrl)) { + $this->_baseAuthUrl = $this->defaultBaseAuthUrl(); + } + return $this->_baseAuthUrl; + } + + /** + * Returns default auth providers list. + * @return ProviderInterface[] auth providers list. + */ + protected function defaultProviders() + { + /** @var $collection \yii\authclient\provider\Collection */ + $collection = Yii::$app->getComponent($this->providerCollection); + return $collection->getProviders(); + } + + /** + * Composes default base auth URL configuration. + * @return array base auth URL configuration. + */ + protected function defaultBaseAuthUrl() + { + $baseAuthUrl = [ + Yii::$app->controller->getRoute() + ]; + $params = $_GET; + unset($params[$this->providerIdGetParamName]); + $baseAuthUrl = array_merge($baseAuthUrl, $params); + return $baseAuthUrl; + } + + /** + * Outputs external service auth link. + * @param ProviderInterface $service external auth service instance. + * @param string $text link text, if not set - default value will be generated. + * @param array $htmlOptions link HTML options. + */ + public function providerLink($service, $text = null, array $htmlOptions = []) + { + if ($text === null) { + $text = Html::tag('span', ['class' => 'auth-icon ' . $service->getName()], ''); + $text .= Html::tag('span', ['class' => 'auth-title'], $service->getTitle()); + } + if (!array_key_exists('class', $htmlOptions)) { + $htmlOptions['class'] = 'auth-link ' . $service->getName(); + } + if ($this->popupMode) { + if (isset($service->popupWidth)) { + $htmlOptions['data-popup-width'] = $service->popupWidth; + } + if (isset($service->popupHeight)) { + $htmlOptions['data-popup-height'] = $service->popupHeight; + } + } + echo Html::a($text, $this->createProviderUrl($service), $htmlOptions); + } + + /** + * Composes external service auth URL. + * @param ProviderInterface $provider external auth service instance. + * @return string auth URL. + */ + public function createProviderUrl($provider) + { + $this->autoRender = false; + $url = $this->getBaseAuthUrl(); + $url[$this->providerIdGetParamName] = $provider->getId(); + return Html::url($url); + } + + /** + * Renders the main content, which includes all external services links. + */ + protected function renderMainContent() + { + echo Html::beginTag('ul', ['class' => 'auth-services clear']); + foreach ($this->getProviders() as $externalService) { + echo Html::beginTag('li', ['class' => 'auth-service']); + $this->providerLink($externalService); + echo Html::endTag('li'); + } + echo Html::endTag('ul'); + } + + /** + * Initializes the widget. + */ + public function init() + { + if ($this->popupMode) { + $view = Yii::$app->getView(); + ChoiceAsset::register($view); + $view->registerJs("\$('#" . $this->getId() . "').authchoice();"); + } + $this->mainContainerHtmlOptions['id'] = $this->getId(); + echo Html::beginTag('div', $this->mainContainerHtmlOptions); + } + + /** + * Runs the widget. + */ + public function run() + { + if ($this->autoRender) { + $this->renderMainContent(); + } + echo Html::endTag('div'); + } +} \ No newline at end of file diff --git a/extensions/yii/authclient/widgets/ChoiceAsset.php b/extensions/yii/authclient/widgets/ChoiceAsset.php new file mode 100644 index 0000000..c5fcbef --- /dev/null +++ b/extensions/yii/authclient/widgets/ChoiceAsset.php @@ -0,0 +1,27 @@ + + * @since 2.0 + */ +class ChoiceAsset extends AssetBundle +{ + public $sourcePath = '@yii/authclient/widgets/assets'; + public $js = [ + 'authchoice.js', + ]; + public $depends = [ + 'yii\web\YiiAsset', + ]; +} \ No newline at end of file diff --git a/extensions/yii/authclient/widgets/assets/authchoice.js b/extensions/yii/authclient/widgets/assets/authchoice.js new file mode 100644 index 0000000..b0aa885 --- /dev/null +++ b/extensions/yii/authclient/widgets/assets/authchoice.js @@ -0,0 +1,53 @@ +jQuery(function($) { + var authChoicePopup; + + $.fn.authchoice = function(options) { + options = $.extend({ + popup: { + resizable: 'yes', + scrollbars: 'no', + toolbar: 'no', + menubar: 'no', + location: 'no', + directories: 'no', + status: 'yes', + width: 450, + height: 380 + } + }, options); + + return this.each(function() { + var container = $(this); + + container.find('a').on('click', function(e) { + e.preventDefault(); + if (authChoicePopup !== undefined) { + authChoicePopup.close(); + } + var url = this.href; + var popupOptions = options.popup; + + var localPopupWidth = this.getAttribute('data-popup-width'); + if (localPopupWidth) { + popupOptions.width = localPopupWidth; + } + var localPopupHeight = this.getAttribute('data-popup-height'); + if (localPopupWidth) { + popupOptions.height = localPopupHeight; + } + + popupOptions.left = (window.screen.width - options.popup.width) / 2; + popupOptions.top = (window.screen.height - options.popup.height) / 2; + + var popupFeatureParts = []; + for (var propName in popupOptions) { + popupFeatureParts.push(propName + '=' + popupOptions[propName]); + } + var popupFeature = popupFeatureParts.join(','); + + authChoicePopup = window.open(url, 'yii_auth_choice', popupFeature); + authChoicePopup.focus(); + }); + }); + }; +});