├── Module.php ├── README.md ├── Survey.php ├── SurveyAsset.php ├── SurveyInterface.php ├── SurveyWidgetAsset.php ├── assets ├── css │ ├── preloader.css │ ├── preloader.css.map │ ├── preloader.scss │ ├── survey.css │ ├── survey.css.map │ └── survey.scss └── js │ ├── promise.min.js │ ├── survey.js │ └── survey.widget.js ├── composer.json ├── controllers ├── DefaultController.php └── QuestionController.php ├── messages ├── en │ └── survey.php └── ru │ └── survey.php ├── migrations ├── m181018_070730_create_table_survey.php ├── m181018_070730_create_table_survey_answer.php ├── m181018_070730_create_table_survey_question.php ├── m181018_070730_create_table_survey_stat.php ├── m181018_070730_create_table_survey_type.php ├── m181018_070730_create_table_survey_user_answer.php ├── m181018_070730_foreign_keys.php └── m190918_224430_private_survey.php ├── models ├── Survey.php ├── SurveyAnswer.php ├── SurveyQuestion.php ├── SurveyStat.php ├── SurveyType.php ├── SurveyUserAnswer.php └── search │ ├── SurveySearch.php │ └── SurveyStatSearch.php ├── views ├── answers │ ├── 1.php │ ├── 10.php │ ├── 2.php │ ├── 3.php │ ├── 4.php │ ├── 5.php │ ├── 6.php │ ├── 7.php │ ├── 8.php │ ├── 9.php │ ├── _form.php │ └── view │ │ ├── 1.php │ │ ├── 10.php │ │ ├── 2.php │ │ ├── 3.php │ │ ├── 4.php │ │ ├── 5.php │ │ ├── 6.php │ │ ├── 7.php │ │ ├── 8.php │ │ ├── 9.php │ │ └── _form.php ├── default │ ├── _form.php │ ├── create.php │ ├── index.php │ ├── respondents.php │ ├── restrictedUsers.php │ ├── update.php │ └── view.php ├── question │ ├── _form.php │ ├── _viewForm.php │ └── cardView.php └── widget │ ├── answers │ ├── 1.php │ ├── 10.php │ ├── 2.php │ ├── 3.php │ ├── 4.php │ ├── 5.php │ ├── 6.php │ ├── 7.php │ ├── 8.php │ ├── 9.php │ └── _form.php │ ├── default │ ├── closed.php │ ├── index.php │ ├── success.php │ └── unavailable.php │ └── question │ └── _form.php └── widgetControllers ├── DefaultController.php └── QuestionController.php /Module.php: -------------------------------------------------------------------------------- 1 | null, 23 | 'uploadsPath' => null, 24 | ]; 25 | 26 | /** 27 | * @inheritdoc 28 | */ 29 | public function init() 30 | { 31 | 32 | if (empty($this->controllerNamespace)) { 33 | $this->controllerNamespace = \Yii::$app->controllerNamespace === 'backend\controllers' 34 | ? 'onmotion\survey\controllers' 35 | : 'onmotion\survey\widgetControllers'; 36 | } 37 | 38 | parent::init(); 39 | 40 | if (empty($this->params['uploadsUrl'])) { 41 | throw new UserException("You must set uploadsUrl param in the config. Please see the documentation for more information."); 42 | } else { 43 | $this->params['uploadsUrl'] = rtrim($this->params['uploadsUrl'], '/'); 44 | } 45 | if (empty($this->params['uploadsPath'])) { 46 | throw new UserException("You must set uploadsPath param in the config. Please see the documentation for more information."); 47 | } else { 48 | $this->params['uploadsPath'] = FileHelper::normalizePath($this->params['uploadsPath']); 49 | } 50 | 51 | $this->userClass = \Yii::$app->user->identityClass; 52 | 53 | \Yii::setAlias('@surveyRoot', __DIR__); 54 | 55 | // set up i8n 56 | if (empty(\Yii::$app->i18n->translations['survey'])) { 57 | \Yii::$app->i18n->translations['survey'] = [ 58 | 'class' => 'yii\i18n\PhpMessageSource', 59 | 'basePath' => '@surveyRoot/messages', 60 | ]; 61 | } 62 | 63 | $view = \Yii::$app->getView(); 64 | SurveyAsset::register($view); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Survey module for Yii2 application 3 | -- 4 | 5 | [![Latest Stable Version](https://poser.pugx.org/onmotion/yii2-survey/v/stable)](https://packagist.org/packages/onmotion/yii2-survey) 6 | [![Total Downloads](https://poser.pugx.org/onmotion/yii2-survey/downloads)](https://packagist.org/packages/onmotion/yii2-survey) 7 | [![Monthly Downloads](https://poser.pugx.org/onmotion/yii2-survey/d/monthly)](https://packagist.org/packages/onmotion/yii2-survey) 8 | [![License](https://poser.pugx.org/onmotion/yii2-survey/license)](https://packagist.org/packages/onmotion/yii2-survey) 9 | 10 | 11 | >! Note: the module under active developing, so it may have vary errors and unstable work. 12 | > Highly appreciate your PR. 13 | 14 | ![fluent](https://github.com/onmotion/yii2-survey/blob/docs/examples/front-short.png?raw=true) 15 | 16 | 17 | Installation 18 | -- 19 | 20 | * Just run: 21 | 22 | composer require onmotion/yii2-survey 23 | 24 | or add 25 | 26 | "onmotion/yii2-survey": "*" 27 | 28 | to the require section of your composer.json file. 29 | 30 | * apply migration: 31 | 32 | 33 | ```sh 34 | php yii migrate --migrationPath=@vendor/onmotion/yii2-survey/migrations 35 | ``` 36 | 37 | * Define module to your config: 38 | 39 | ```php 40 | 'modules' => [ 41 | //... 42 | 'survey' => [ 43 | 'class' => '\onmotion\survey\Module', 44 | 'params' => [ 45 | 'uploadsUrl' => 'http://advanced-frontend.lh/uploads/survey/', // full URL of the folder where the images will be uploaded. 46 | // 'uploadsUrl' => '/uploads/survey/', // or for basic 47 | 'uploadsPath' => '@frontend/web/uploads/survey/', // absolute path to the folder where images will be saved. 48 | ], 49 | // 'as access' => [ 50 | // 'class' => AccessControl::class, 51 | // 'except' => ['default/done'], 52 | // 'only' => ['default*'], 53 | // 'rules' => [ 54 | // [ 55 | // 'allow' => true, 56 | // 'roles' => ['survey'], 57 | // ], 58 | // ], 59 | // ], 60 | ], 61 | //... 62 | ] 63 | ``` 64 | 65 | don't forget change your own params. 66 | 67 | Usage 68 | -- 69 | 70 | If you are using the Yii basic template, you must manually define `$controllerNamespace` for module. 71 | 72 | *onmotion\survey\controllers* - backend (admin/create/edit surveys) 73 | 74 | *onmotion\survey\widgetControllers* - default (for widget) 75 | 76 | Now go to `/survey` in your backend and create a survey. 77 | 78 | ![fluent](https://github.com/onmotion/yii2-survey/blob/docs/examples/back-list.png?raw=true) 79 | 80 | After that you can select Survey entities and show it for user, for example: 81 | 82 | ```php 83 | echo \onmotion\survey\Survey::widget([ 84 | 'surveyId' => 1 85 | ]); 86 | ``` 87 | 88 | ![fluent](https://github.com/onmotion/yii2-survey/blob/docs/examples/front.png?raw=true) 89 | 90 | Admin: 91 | 92 | ![fluent](https://github.com/onmotion/yii2-survey/blob/docs/examples/back-create.png?raw=true) 93 | 94 | ![fluent](https://github.com/onmotion/yii2-survey/blob/docs/examples/back-review.png?raw=true) -------------------------------------------------------------------------------- /Survey.php: -------------------------------------------------------------------------------- 1 | i18n->translations['survey'])) { 26 | \Yii::$app->i18n->translations['survey'] = [ 27 | 'class' => 'yii\i18n\PhpMessageSource', 28 | 'basePath' => '@surveyRoot/messages', 29 | ]; 30 | } 31 | 32 | \Yii::setAlias('@surveyRoot', __DIR__); 33 | 34 | parent::init(); 35 | } 36 | 37 | public function getViewPath() 38 | { 39 | return \Yii::getAlias('@surveyRoot/views'); 40 | } 41 | 42 | public function beforeRun() 43 | { 44 | // $assignedModel = SurveyStat::getAssignedUserStat(\Yii::$app->user->getId(), $this->surveyId); 45 | // if (empty($assignedModel)) { 46 | // throw new ForbiddenHttpException(); 47 | // } 48 | return parent::beforeRun(); 49 | } 50 | 51 | public function run() 52 | { 53 | $view = $this->getView(); 54 | SurveyWidgetAsset::register($view); 55 | 56 | $survey = $this->findModel($this->surveyId); 57 | if (!$survey || !$survey->isAccessibleByCurrentUser) { 58 | return $this->renderUnavailable(); 59 | } 60 | 61 | $status = $survey->getStatus(); 62 | if ($status !== 'active') { 63 | return $this->renderClosed(); 64 | } 65 | 66 | $assignedModel = SurveyStat::getAssignedUserStat(\Yii::$app->user->getId(), $this->surveyId); 67 | if (empty($assignedModel)) { 68 | SurveyStat::assignUser(\Yii::$app->user->getId(), $this->surveyId); 69 | $assignedModel = SurveyStat::getAssignedUserStat(\Yii::$app->user->getId(), $this->surveyId); 70 | } else { 71 | // if ($assignedModel->survey_stat_is_done){ 72 | // return $this->renderClosed(); 73 | // } 74 | } 75 | 76 | 77 | if ($assignedModel->survey_stat_started_at === null) { 78 | $assignedModel->survey_stat_started_at = new Expression('NOW()'); 79 | $assignedModel->save(false); 80 | } 81 | 82 | return $this->renderSurvey($this->surveyId, $assignedModel); 83 | } 84 | 85 | private function renderClosed() 86 | { 87 | echo $this->render('widget/default/closed'); 88 | } 89 | 90 | private function renderUnavailable() 91 | { 92 | echo $this->render('widget/default/unavailable'); 93 | } 94 | 95 | private function renderSurvey($id, $stat) 96 | { 97 | $survey = $this->findModel($id); 98 | echo $this->render('widget/default/index', ['survey' => $survey, 'stat' => $stat]); 99 | } 100 | 101 | protected function findModel($id) 102 | { 103 | if (($model = \onmotion\survey\models\Survey::findOne($id)) !== null) { 104 | return $model; 105 | } else { 106 | throw new NotFoundHttpException('The requested page does not exist.'); 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /SurveyAsset.php: -------------------------------------------------------------------------------- 1 | sourcePath = __DIR__ . '/assets'; 20 | parent::init(); 21 | } 22 | 23 | public $publishOptions = [ 24 | 'forceCopy' => YII_ENV_DEV //dev 25 | ]; 26 | 27 | public $css = [ 28 | 'css/survey.css', 29 | 'css/preloader.css', 30 | ]; 31 | public $js = [ 32 | 'js/survey.js', 33 | ]; 34 | public $depends = [ 35 | 'yii\web\YiiAsset', 36 | ]; 37 | } -------------------------------------------------------------------------------- /SurveyInterface.php: -------------------------------------------------------------------------------- 1 | sourcePath = __DIR__ . '/assets'; 20 | parent::init(); 21 | } 22 | 23 | public $publishOptions = [ 24 | 'forceCopy' => YII_ENV_DEV //dev 25 | ]; 26 | 27 | public $css = [ 28 | 'css/survey.css', 29 | 'css/preloader.css', 30 | ]; 31 | public $js = [ 32 | 'js/promise.min.js', 33 | 'js/survey.widget.js', 34 | ]; 35 | public $depends = [ 36 | 'yii\web\YiiAsset', 37 | ]; 38 | } -------------------------------------------------------------------------------- /assets/css/preloader.css: -------------------------------------------------------------------------------- 1 | .preloader{width:100%;height:100%;position:absolute;left:0;top:0;background:rgba(255,255,255,0.6);z-index:100}.cssload-spin-box{position:absolute;margin:auto;left:0;top:0;bottom:0;right:0;width:15px;height:15px;border-radius:100%;box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf;-o-box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf;-ms-box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf;-webkit-box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf;-moz-box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf;animation:cssload-spin ease infinite 4.6s;-o-animation:cssload-spin ease infinite 4.6s;-ms-animation:cssload-spin ease infinite 4.6s;-webkit-animation:cssload-spin ease infinite 4.6s;-moz-animation:cssload-spin ease infinite 4.6s}@keyframes cssload-spin{0%, 2 | 100%{-webkit-box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf;box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf}25%{-webkit-box-shadow:-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf,15px 15px #4f4d49;box-shadow:-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf,15px 15px #4f4d49}50%{-webkit-box-shadow:-15px -15px #4f4d49,15px -15px #dfdfdf,15px 15px #4f4d49,-15px 15px #dfdfdf;box-shadow:-15px -15px #4f4d49,15px -15px #dfdfdf,15px 15px #4f4d49,-15px 15px #dfdfdf}75%{-webkit-box-shadow:15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49;box-shadow:15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49}}@-webkit-keyframes cssload-spin{0%, 3 | 100%{-webkit-box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf;box-shadow:15px 15px #4f4d49,-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf}25%{-webkit-box-shadow:-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf,15px 15px #4f4d49;box-shadow:-15px 15px #dfdfdf,-15px -15px #4f4d49,15px -15px #dfdfdf,15px 15px #4f4d49}50%{-webkit-box-shadow:-15px -15px #4f4d49,15px -15px #dfdfdf,15px 15px #4f4d49,-15px 15px #dfdfdf;box-shadow:-15px -15px #4f4d49,15px -15px #dfdfdf,15px 15px #4f4d49,-15px 15px #dfdfdf}75%{-webkit-box-shadow:15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49;box-shadow:15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49}} 4 | -------------------------------------------------------------------------------- /assets/css/preloader.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AAAA,UAAU;EACN,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,QAAQ,EAAE,QAAQ;EAClB,IAAI,EAAE,CAAC;EACP,GAAG,EAAE,CAAC;EACN,UAAU,EAAE,wBAAwB;EACpC,OAAO,EAAE,GAAG;;AAGhB,iBAAkB;EACd,QAAQ,EAAE,QAAQ;EAClB,MAAM,EAAE,IAAI;EACZ,IAAI,EAAE,CAAC;EACP,GAAG,EAAE,CAAC;EACN,MAAM,EAAE,CAAC;EACT,KAAK,EAAE,CAAC;EACR,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,8EAA4G;EACxH,aAAa,EAAE,8EAA4G;EAC3H,cAAc,EAAE,8EAA4G;EAC5H,kBAAkB,EAAE,8EAA4G;EAChI,eAAe,EAAE,8EAA4G;EAC7H,SAAS,EAAE,+BAA+B;EAC1C,YAAY,EAAE,+BAA+B;EAC7C,aAAa,EAAE,+BAA+B;EAC9C,iBAAiB,EAAE,+BAA+B;EAClD,cAAc,EAAE,+BAA+B;;AAInD,uBAcC;EAbG;QACK;IACD,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA8E;AAIlG,0BAcC;EAbG;QACK;IACD,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA8E;AAIlG,2BAcC;EAbG;QACK;IACD,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA8E;AAIlG,+BAcC;EAbG;QACK;IACD,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA8E;AAIlG,4BAcC;EAbG;QACK;IACD,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA4G;EAE5H,GAAI;IACA,UAAU,EAAE,8EAA8E", 4 | "sources": ["preloader.scss"], 5 | "names": [], 6 | "file": "preloader.css" 7 | } 8 | -------------------------------------------------------------------------------- /assets/css/preloader.scss: -------------------------------------------------------------------------------- 1 | .preloader{ 2 | width: 100%; 3 | height: 100%; 4 | position: absolute; 5 | left: 0; 6 | top: 0; 7 | background: rgba(255, 255, 255, 0.6); 8 | z-index: 100; 9 | } 10 | 11 | .cssload-spin-box { 12 | position: absolute; 13 | margin: auto; 14 | left: 0; 15 | top: 0; 16 | bottom: 0; 17 | right: 0; 18 | width: 15px; 19 | height: 15px; 20 | border-radius: 100%; 21 | box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 22 | -o-box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 23 | -ms-box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 24 | -webkit-box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 25 | -moz-box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 26 | animation: cssload-spin ease infinite 4.6s; 27 | -o-animation: cssload-spin ease infinite 4.6s; 28 | -ms-animation: cssload-spin ease infinite 4.6s; 29 | -webkit-animation: cssload-spin ease infinite 4.6s; 30 | -moz-animation: cssload-spin ease infinite 4.6s; 31 | } 32 | 33 | 34 | @keyframes cssload-spin { 35 | 0%, 36 | 100% { 37 | box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 38 | } 39 | 25% { 40 | box-shadow: -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73); 41 | } 42 | 50% { 43 | box-shadow: -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223); 44 | } 45 | 75% { 46 | box-shadow: 15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49; 47 | } 48 | } 49 | 50 | @-o-keyframes cssload-spin { 51 | 0%, 52 | 100% { 53 | box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 54 | } 55 | 25% { 56 | box-shadow: -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73); 57 | } 58 | 50% { 59 | box-shadow: -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223); 60 | } 61 | 75% { 62 | box-shadow: 15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49; 63 | } 64 | } 65 | 66 | @-ms-keyframes cssload-spin { 67 | 0%, 68 | 100% { 69 | box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 70 | } 71 | 25% { 72 | box-shadow: -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73); 73 | } 74 | 50% { 75 | box-shadow: -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223); 76 | } 77 | 75% { 78 | box-shadow: 15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49; 79 | } 80 | } 81 | 82 | @-webkit-keyframes cssload-spin { 83 | 0%, 84 | 100% { 85 | box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 86 | } 87 | 25% { 88 | box-shadow: -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73); 89 | } 90 | 50% { 91 | box-shadow: -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223); 92 | } 93 | 75% { 94 | box-shadow: 15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49; 95 | } 96 | } 97 | 98 | @-moz-keyframes cssload-spin { 99 | 0%, 100 | 100% { 101 | box-shadow: 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223); 102 | } 103 | 25% { 104 | box-shadow: -15px 15px rgb(223,223,223), -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73); 105 | } 106 | 50% { 107 | box-shadow: -15px -15px rgb(79,77,73), 15px -15px rgb(223,223,223), 15px 15px rgb(79,77,73), -15px 15px rgb(223,223,223); 108 | } 109 | 75% { 110 | box-shadow: 15px -15px #dfdfdf, 15px 15px #4f4d49, -15px 15px #dfdfdf, -15px -15px #4f4d49; 111 | } 112 | } -------------------------------------------------------------------------------- /assets/css/survey.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["survey.scss"],"names":[],"mappings":"AAIA;EAEE;EACA;;;AAGF;EACE;;;AAIA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAIJ;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAIJ;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;;AAQJ;EACE;;;AAMJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIJ;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE,kBA7KS;EA8KT;EACA;;AAEA;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;;AAEA;EACE;;AAKJ;EACE;;AAEA;EACE;EACA;EAEA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAKN;EAME;;AALA;EACE;EACA;;AAKF;EACE;;AAGF;EACE;;AAGF;EACE,OAjSS;EAkST;EACA;;AAGF;EACE;;AAIJ;EACE;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAMN;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAIJ;EACE;;AAEA;EACE;;AAIJ;EACE;;AAEA;EACE;EACA;;AAKJ;EACE;EACA;;AAEA;EACE;;AAKN;EAEE;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;;;AAIJ;EACE;EACA;;;AAIA;EACE;;;AAKF;EACE;;AAGF;EACE;;AAIF;EACE;;AAGF;EACE;EACA;;;AAIJ;EACE;;AAEA;EACE;;AAGF;EACE;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAIJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAKN;EACE;;AAKN;EACE;;;AAOF;EACE;;;AAKF;EACE;;AAEA;EACE;EACA;;AAIJ;EACE;;AAEA;EACE;;;AAKN;EACE,YA/jBa;EAgkBb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;;;AAQN;EACE;;AAGF;EACE;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;;;AAMF;AAAA;AAAA;AAAA;EAEE;;AAEA;AAAA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;AAAA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;EACE;;;AAON;EACE;;AAEA;EACE;;AAGE;EACE;EACA;;;AASN;EACE;;;AAMJ;EACE;;AAGF;EACE;EACA;;AAEA;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;;AAMR;EACE;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA,YAtxBa;EAuxBb;;AAEA;EACE;EACA;;AAEA;EACE;;AAGF;EACE;EACA;EACA;;AAKF;EACE;EACA;EACA;;AAEA;EACE;;AAMR;EACE;;AAEA;EACE;;AAOA;EACE;EACA;EACA;;AAEA;EACE;;AAIA;EACE;EACA;;AAMR;EACE;;AAEA;EACE;;AAIJ;EACE;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAEA;EACE;;AAIJ;EACE;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAIF;EACE;;AAIJ;EACE;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAWA;EACE;EACA;;AAKJ;EACE;EACA;;AAEA;EACE;EACA;;AAEA;EACE;;AAKN;EACE;;;AAKF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAOF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAIA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAKA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAKJ;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;AAKJ;EACE;;;AAKE;EACE;;AAEA;EACE;EACA;;AAGF;EACE;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;EACA;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMN;EAIQ;IACE;IACA;IACA;;;AAOV;EACE","file":"survey.css"} -------------------------------------------------------------------------------- /assets/js/promise.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Promise=t()}(this,function(){"use strict";function e(){}function t(e,t){for(;3===e._state;)e=e._value;0!==e._state?(e._handled=!0,f._immediateFn(function(){var i=1===e._state?t.onFulfilled:t.onRejected;if(null!==i){var r;try{r=i(e._value)}catch(e){return void o(t.promise,e)}n(t.promise,r)}else(1===e._state?n:o)(t.promise,e._value)})):e._deferreds.push(t)}function n(e,t){try{if(t===e)throw new TypeError("A promise cannot be resolved with itself.");if(t&&("object"==typeof t||"function"==typeof t)){var n=t.then;if(t instanceof f)return e._state=3,e._value=t,void i(e);if("function"==typeof n)return void r(function(e,t){return function(){e.apply(t,arguments)}}(n,t),e)}e._state=1,e._value=t,i(e)}catch(t){o(e,t)}}function o(e,t){e._state=2,e._value=t,i(e)}function i(e){2===e._state&&0===e._deferreds.length&&f._immediateFn(function(){e._handled||f._unhandledRejectionFn(e._value)});for(var n=0,o=e._deferreds.length;o>n;n++)t(e,e._deferreds[n]);e._deferreds=null}function r(e,t){var i=!1;try{e(function(e){i||(i=!0,n(t,e))},function(e){i||(i=!0,o(t,e))})}catch(e){if(i)return;i=!0,o(t,e)}}function f(e){if(!(this instanceof f))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],r(e,this)}var u=setTimeout,c=f.prototype;return c.catch=function(e){return this.then(null,e)},c.then=function(n,o){var i=new this.constructor(e);return t(this,new function(e,t,n){this.onFulfilled="function"==typeof e?e:null,this.onRejected="function"==typeof t?t:null,this.promise=n}(n,o,i)),i},f.all=function(e){return new f(function(t,n){function o(e,f){try{if(f&&("object"==typeof f||"function"==typeof f)){var u=f.then;if("function"==typeof u)return void u.call(f,function(t){o(e,t)},n)}i[e]=f,0==--r&&t(i)}catch(e){n(e)}}if(!e||void 0===e.length)throw new TypeError("Promise.all accepts an array");var i=Array.prototype.slice.call(e);if(0===i.length)return t([]);for(var r=i.length,f=0;i.length>f;f++)o(f,i[f])})},f.resolve=function(e){return e&&"object"==typeof e&&e.constructor===f?e:new f(function(t){t(e)})},f.reject=function(e){return new f(function(t,n){n(e)})},f.race=function(e){return new f(function(t,n){for(var o=0,i=e.length;i>o;o++)e[o].then(t,n)})},f._immediateFn="function"==typeof setImmediate&&function(e){setImmediate(e)}||function(e){u(e,0)},f._unhandledRejectionFn=function(e){void 0!==console&&console&&console.warn("Possible Unhandled Promise Rejection:",e)},f}); -------------------------------------------------------------------------------- /assets/js/survey.js: -------------------------------------------------------------------------------- 1 | ;(function ($) { 2 | "use strict"; 3 | 4 | /** 5 | * 6 | */ 7 | function Survey() { 8 | 9 | $(document).on('pjax:end', function (e, contents, options) { 10 | console.log(e); 11 | if (e.target.id === 'survey-questions-append') { 12 | var appendContainer = $('#survey-questions-append').find('.survey-question-pjax-container'); 13 | appendContainer.appendTo('#survey-questions'); 14 | } 15 | }); 16 | 17 | $(document).on('pjax:timeout', function (event) { 18 | // Prevent default timeout redirection behavior 19 | console.log(event); 20 | event.preventDefault(); 21 | }); 22 | 23 | $(document).on('pjax:error', function (event, xhr, textStatus, error, options) { 24 | console.log(event); 25 | event.preventDefault(); 26 | }); 27 | 28 | 29 | $(document).on('click', '.survey-question-submit, .user-assign-submit', pseudoSubmit); 30 | 31 | function pseudoSubmit(e) { 32 | e.preventDefault(); 33 | var $this = $(this); 34 | var data = $this.data(); 35 | var action = data.action; 36 | var $form = $this.closest('form'); 37 | console.log($form); 38 | if ($form && action) { 39 | $form.attr('action', action).submit(); 40 | } else { 41 | console.log('Error'); 42 | } 43 | } 44 | 45 | $(document).on('click', '.checkbox-updatable', function (e) { 46 | var container = $(this).closest('[data-pjax-container]'); 47 | container.find('.update-question-btn').click(); 48 | }); 49 | 50 | $(document).on('click', '.submit-on-click', function (e) { 51 | var container = $(this).closest('[data-pjax-container]'); 52 | container.find('button[type=submit]').click(); 53 | }); 54 | 55 | 56 | async function submitAllForms() { 57 | var forms = []; 58 | var $body = $('body'); 59 | $body.toggleClass('survey-loading'); 60 | var btn = $(this).find('button'); 61 | btn.prop('disabled', true); 62 | var defaultText = btn.data('default-text') || ''; 63 | btn.html(''); 64 | var allFormsIsValid = true; 65 | 66 | $(document).find('form.form-inline').each(function (i, el) { 67 | forms.push($(el)); 68 | }); 69 | 70 | for (var item of forms) { 71 | try { 72 | await confirmForm(item); 73 | } catch (err) { 74 | allFormsIsValid = false; 75 | } 76 | } 77 | 78 | if (allFormsIsValid) { 79 | location.href = $('#save').data('action'); 80 | } else { 81 | btn.prop('disabled', false); 82 | btn.html(defaultText); 83 | $body.toggleClass('survey-loading'); 84 | } 85 | } 86 | 87 | $(document).on('click', '#save', submitAllForms); 88 | 89 | $(document).on('click', '.close-btn', function (e) { 90 | $(this).parent().toggleClass('opened'); 91 | $('body').toggleClass('modal-open'); 92 | }); 93 | 94 | $(document).on('click', '.respondents-toggle', function (e) { 95 | $('#respondents-modal').toggleClass('opened'); 96 | $('body').toggleClass('modal-open'); 97 | }); 98 | 99 | $(document).on('click', '.restricted-users-toggle', function (e) { 100 | $('#restricted-users-modal').toggleClass('opened'); 101 | $('body').toggleClass('modal-open'); 102 | }); 103 | 104 | 105 | function confirmForm(form) { 106 | return new Promise((resolve, reject) => { 107 | var container = form.closest('[data-pjax-container]'); 108 | form.submit(); 109 | container.on('afterValidate', function (event, messages, errorAttributes) { 110 | if (errorAttributes.length > 0) { 111 | reject(messages); 112 | } 113 | }); 114 | container.on('pjax:end', function (e) { 115 | console.log(e); 116 | resolve(e); 117 | }); 118 | container.on('pjax:error', function (e) { 119 | console.log(e); 120 | reject(e); 121 | }); 122 | }); 123 | } 124 | 125 | 126 | var showProgress; 127 | showProgress = function showProgress(container) { 128 | try { 129 | container.prepend('
'); 130 | } catch (err) { 131 | console.log(e.message); 132 | } 133 | $('.preloader').fadeIn(); 134 | }; 135 | 136 | var hideProgress; 137 | (hideProgress = function hideProgress(container = null) { 138 | try { 139 | if (container !== null) { 140 | $(container).find('.preloader').fadeOut(500, function () { 141 | $(this).remove(); 142 | }); 143 | } else { 144 | $('.preloader').fadeOut(500, function () { 145 | $(this).remove(); 146 | }); 147 | } 148 | } catch (err) { 149 | console.log(e.message); 150 | } 151 | })(); 152 | 153 | $(document).on('pjax:start', function (e) { 154 | if ((e.target.id).indexOf('survey-questions-pjax-') !== -1) { 155 | showProgress($('#' + e.target.id).find('.survey-block ')); 156 | } 157 | }); 158 | 159 | $(document).on('pjax:complete', function (e) { 160 | if ((e.target.id).indexOf('survey-questions-pjax-') !== -1 || (e.target.id === 'survey-questions-append')) { 161 | hideProgress($('#' + e.target.id)); 162 | } 163 | }); 164 | } 165 | 166 | $.fn['survey'] = function () { 167 | console.log('survey init'); 168 | if (!$.data(this, 'plugin_Survey')) { 169 | return $.data(this, 'plugin_Survey', 170 | new Survey()); 171 | } 172 | } 173 | 174 | })(window.jQuery); -------------------------------------------------------------------------------- /assets/js/survey.widget.js: -------------------------------------------------------------------------------- 1 | ;(function ($) { 2 | "use strict"; 3 | 4 | /** 5 | * 6 | */ 7 | function SurveyWidget(options) { 8 | 9 | this.id = options.id || null; 10 | 11 | $(document).on('pjax:end', function (e, contents, options) { 12 | console.log(e); 13 | if (e.target.id === 'survey-questions-append') { 14 | var appendContainer = $('#survey-questions-append').find('.survey-question-pjax-container'); 15 | appendContainer.appendTo('#survey-questions'); 16 | } 17 | }); 18 | 19 | $(document).on('pjax:timeout', function (event) { 20 | // Prevent default timeout redirection behavior 21 | console.log(event); 22 | event.preventDefault(); 23 | }); 24 | 25 | $(document).on('pjax:error', function (event, xhr, textStatus, error, options) { 26 | console.log(event); 27 | event.preventDefault(); 28 | }); 29 | 30 | var showProgress; 31 | showProgress = function showProgress(container) { 32 | try { 33 | container.prepend('
'); 34 | } catch (err) { 35 | console.log(e.message); 36 | } 37 | $('.preloader').fadeIn(); 38 | }; 39 | 40 | var hideProgress = function hideProgress(container) { 41 | container = container || null; 42 | try { 43 | if (container !== null) { 44 | $(container).find('.preloader').fadeOut(500, function () { 45 | $(this).remove(); 46 | }); 47 | } else { 48 | $('.preloader').fadeOut(500, function () { 49 | $(this).remove(); 50 | }); 51 | } 52 | } catch (err) { 53 | console.log(e.message); 54 | } 55 | }; 56 | hideProgress(); 57 | 58 | $(document).on('pjax:start', function (e) { 59 | if ((e.target.id).indexOf('survey-questions-pjax-') !== -1) { 60 | showProgress($('#' + e.target.id).find('.survey-block ')); 61 | } 62 | }); 63 | 64 | $(document).on('pjax:complete', function (e) { 65 | if ((e.target.id).indexOf('survey-questions-pjax-') !== -1 || (e.target.id === 'survey-questions-append')) { 66 | hideProgress($('#' + e.target.id)); 67 | } 68 | }); 69 | 70 | 71 | $(document).on('afterValidateAttribute', function (event, attribute, messages) { 72 | if (messages.length === 0) { 73 | var submitBtn = $(event.target).find('.btn-submit'); 74 | // submitBtn.showUp(); 75 | // console.log(submitBtn.showUp()); 76 | } 77 | }); 78 | 79 | function createModal() { 80 | $('html').append("\ 81 | "); 96 | } 97 | 98 | function removeModal() { 99 | $('#survey-modal').remove(); 100 | } 101 | 102 | function confirmForm(form) { 103 | return new Promise(function(resolve, reject) { 104 | var container = form.closest('[data-pjax-container]'); 105 | form.submit(); 106 | container.off('afterValidate').on('afterValidate', function (event, messages, errorAttributes) { 107 | if (errorAttributes.length > 0) { 108 | reject(messages); 109 | } else { 110 | resolve(true); 111 | } 112 | }); 113 | 114 | container.off('pjax:error').on('pjax:error', function (e) { 115 | // console.log(e); 116 | reject(e); 117 | }); 118 | setTimeout(function() { 119 | resolve(true); 120 | }, 5000); 121 | }); 122 | 123 | } 124 | 125 | var that = this; 126 | 127 | function submitAllForms() { 128 | var forms = []; 129 | var $body = $('body'); 130 | $body.toggleClass('survey-loading'); 131 | var btn = $(this); 132 | btn.prop('disabled', true); 133 | var defaultText = btn.data('default-text') || ''; 134 | btn.html(''); 135 | var allFormsIsValid = true; 136 | console.log(allFormsIsValid); 137 | 138 | $(document).find('form.question-form').each(function (i, el) { 139 | forms.push($(el)); 140 | }); 141 | 142 | var promises = []; 143 | for (var _i = 0; _i < forms.length; _i++) { 144 | var item = forms[_i]; 145 | promises.push(confirmForm(item)); 146 | } 147 | 148 | Promise.all(promises).then(function (resolve) { 149 | var csrfParam = $('meta[name="csrf-param"]').attr("content"); 150 | var csrfToken = $('meta[name="csrf-token"]').attr("content"); 151 | var data = {}; 152 | data[csrfParam] = csrfToken; 153 | data.id = that.id; 154 | $.ajax({ 155 | url: btn.data('action') || window.location.pathname, 156 | type: 'post', 157 | data: data, 158 | success: function success(response) { 159 | btn.remove(); 160 | createModal(); 161 | 162 | forms.forEach(f => { 163 | f.find(':input').prop('disabled', true); 164 | f.find('input[data-krajee-slider]').slider('disable'); 165 | }); 166 | 167 | var modal = $('#survey-modal'); 168 | modal.find('.modal-header').html(response.title); 169 | modal.find('.modal-body').html(response.content); 170 | modal.find('.modal-footer').html(response.footer); 171 | modal.modal(); 172 | }, 173 | complete: function complete() { 174 | $body.toggleClass('survey-loading'); 175 | }, 176 | error: function error(err) { 177 | createModal(); 178 | var modal = $('#survey-modal'); 179 | modal.find('.modal-header').html(err.statusText); 180 | modal.find('.modal-body').html(err.responseText); 181 | modal.modal(); 182 | } 183 | }); 184 | }, function (reject) { 185 | btn.prop('disabled', false); 186 | btn.html(defaultText); 187 | $body.toggleClass('survey-loading'); 188 | }); 189 | } 190 | 191 | $(document).on('click', '#s-done', submitAllForms); 192 | 193 | } 194 | 195 | 196 | $.fn.showUp = function () { 197 | if (!this.hasClass('fadeIn')) { 198 | this.removeClass('hidden').addClass('fadeIn'); 199 | } 200 | return this; 201 | }; 202 | 203 | $.fn["surveyWidget"] = function() { 204 | var options = 205 | arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 206 | 207 | console.log("survey widget init"); 208 | if (!$.data(this, "plugin_SurveyWidget")) { 209 | return $.data(this, "plugin_SurveyWidget", new SurveyWidget(options)); 210 | } 211 | }; 212 | 213 | 214 | })(window.jQuery); 215 | 216 | 217 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "onmotion/yii2-survey", 3 | "description": "survey module for Yii2 application", 4 | "type": "yii2-extension", 5 | "keywords": ["yii2","extension","module","widget", "survey", "polls"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Alexandr Kozhevnikov", 10 | "email": "onmotion1@gmail.com", 11 | "homepage": "http://kozhevnikov.me", 12 | "role": "Developer" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.5.0", 17 | "yiisoft/yii2": ">=2.0.1", 18 | "cenotia/yii2-remote-modal": "^1.0", 19 | "kartik-v/yii2-dialog": "^1.0", 20 | "onmotion/yii2-widget-upload-crop": ">=0.5", 21 | "kartik-v/yii2-editable": "^1.7", 22 | "kartik-v/yii2-widget-datetimepicker": "^1.4", 23 | "vova07/yii2-imperavi-widget": "^2.0", 24 | "kartik-v/yii2-widget-select2": "^2.1", 25 | "yiisoft/yii2-imagine": "^2.1", 26 | "kartik-v/yii2-slider": "^1.3", 27 | "kartik-v/yii2-widget-datepicker": "^1.4", 28 | "kartik-v/yii2-helpers": "^1.3", 29 | "kartik-v/yii2-widget-typeahead": "^1.0" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "onmotion\\survey\\": "" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /controllers/QuestionController.php: -------------------------------------------------------------------------------- 1 | [ 32 | 'class' => 'vova07\imperavi\actions\GetImagesAction', 33 | 'url' => $this->module->params['uploadsUrl'] . \Yii::$app->session->get('surveyUploadsSubpath', ''), // URL адрес папки где хранятся изображения. 34 | 'path' => $this->module->params['uploadsPath'] . \Yii::$app->session->get('surveyUploadsSubpath', ''), // Или абсолютный путь к папке с изображениями. 35 | 'options' => ['only' => ['*.jpg', '*.jpeg', '*.png', '*.gif', '*.ico']], // These options are by default. 36 | ], 37 | 'image-upload' => [ 38 | 'class' => 'vova07\imperavi\actions\UploadFileAction', 39 | 'url' => $this->module->params['uploadsUrl'] . \Yii::$app->session->get('surveyUploadsSubpath', ''), // URL адрес папки где хранятся изображения. 40 | 'path' => $this->module->params['uploadsPath'] . \Yii::$app->session->get('surveyUploadsSubpath', ''), // Или абсолютный путь к папке с изображениями. 41 | ], 42 | 'files-get' => [ 43 | 'class' => 'vova07\imperavi\actions\GetFilesAction', 44 | 'url' => $this->module->params['uploadsUrl'] . \Yii::$app->session->get('surveyUploadsSubpath', ''), // URL адрес папки где хранятся изображения. 45 | 'path' => $this->module->params['uploadsPath'] . \Yii::$app->session->get('surveyUploadsSubpath', ''), // Или абсолютный путь к папке с изображениями. 46 | ], 47 | 'file-upload' => [ 48 | 'class' => 'vova07\imperavi\actions\UploadFileAction', 49 | 'url' => $this->module->params['uploadsUrl'] . \Yii::$app->session->get('surveyUploadsSubpath', ''), // URL адрес папки где хранятся изображения. 50 | 'path' => $this->module->params['uploadsPath'] . \Yii::$app->session->get('surveyUploadsSubpath', ''), // Или абсолютный путь к папке с изображениями. 51 | 'uploadOnlyImage' => false, // Для загрузки не только изображений. 52 | ], 53 | 54 | ]; 55 | } 56 | 57 | public function actionCreate($id) 58 | { 59 | $survey = $this->findSurveyModel($id); 60 | $question = new SurveyQuestion(); 61 | $question->loadDefaultValues(); 62 | // $question->survey_question_name = \Yii::t('survey', 'New Question'); 63 | $survey->link('questions', $question); 64 | 65 | for ($i = 1; $i <= 2; ++$i) { 66 | $question->link('answers', (new SurveyAnswer(['survey_answer_sort' => $i]))); 67 | } 68 | 69 | return $this->renderAjax('_form', ['question' => $question]); 70 | } 71 | 72 | public function actionDelete($id) 73 | { 74 | $question = $this->findModel($id); 75 | 76 | if ($question->delete()) { 77 | return ''; 78 | } else { 79 | throw new HttpException('500', 'unable to delete record'); 80 | } 81 | } 82 | 83 | public function actionValidate($id) 84 | { 85 | $question = $this->findModel($id); 86 | $post = \Yii::$app->request->post(); 87 | $action = ArrayHelper::getValue($post, "action"); 88 | $result = []; 89 | \Yii::$app->response->format = Response::FORMAT_JSON; 90 | 91 | $questionIsChanged = false; 92 | 93 | $questionData = ArrayHelper::getValue($post, "SurveyQuestion.{$question->survey_question_id}"); 94 | if (!empty($questionData) && $question->load($questionData, '')) { 95 | $isValid = $question->validate(); 96 | $questionIsChanged = !empty($question->getDirtyAttributes()); 97 | foreach ($question->getErrors() as $attribute => $errors) { 98 | $result["surveyquestion-{$question->survey_question_id}-{$attribute}"] = $errors; 99 | } 100 | if ($isValid) { 101 | $attrsForSave = $question->getAttributes(null, ['survey_question_type']); 102 | $attrs = array_keys($question->getDirtyAttributes(array_keys($attrsForSave))); 103 | $question->save(false, $attrs); 104 | } 105 | } 106 | 107 | $answersData = ArrayHelper::getValue($post, "SurveyAnswer.{$question->survey_question_id}"); 108 | 109 | if (!empty($answersData) 110 | && (count($answersData) === count($question->answers)) 111 | && Model::loadMultiple($question->answers, $answersData, '')) { 112 | foreach ($question->answers as $i => $model) { 113 | if (!$questionIsChanged || $action !== 'delete-answer') { 114 | $model->validate(); 115 | foreach ($model->getErrors() as $attribute => $errors) { 116 | $result["surveyanswer-{$question->survey_question_id}-{$i}-{$attribute}"] = $errors; 117 | } 118 | } 119 | // $model->validate(); 120 | $model->save(); 121 | } 122 | } 123 | 124 | return $result; 125 | } 126 | 127 | public function actionUpdate($id) 128 | { 129 | $question = $this->findModel($id); 130 | 131 | $post = \Yii::$app->request->post(); 132 | 133 | $questionData = ArrayHelper::getValue($post, "SurveyQuestion.{$question->survey_question_id}"); 134 | 135 | $isTypeChanged = false; 136 | if (!empty($questionData) && $question->load($questionData, '') && $question->validate()) { 137 | $isTypeChanged = $question->isAttributeChanged('survey_question_type'); 138 | if ($isTypeChanged) { 139 | $question->changeDefaultValuesOnTypeChange(); 140 | } 141 | $question->save(false); 142 | } 143 | 144 | $answersData = ArrayHelper::getValue($post, "SurveyAnswer.{$question->survey_question_id}"); 145 | if (!empty($answersData) && Model::loadMultiple($question->answers, $answersData, '') && !$isTypeChanged) { 146 | foreach ($question->answers as $answer) { 147 | $answer->save(); 148 | } 149 | } 150 | 151 | $question->refresh(); 152 | 153 | return $this->renderAjax('_form', ['question' => $question]); 154 | } 155 | 156 | public function actionEdit($id) 157 | { 158 | $question = $this->findModel($id); 159 | return $this->renderAjax('_form', ['question' => $question]); 160 | } 161 | 162 | 163 | public function actionAddAnswer($id, $after = null) 164 | { 165 | $question = $this->findModel($id); 166 | $answers = $question->answers; 167 | $lastAnswer = array_values(array_slice($answers, -1))[0]; 168 | 169 | if (!isset($after)) { 170 | $sort = ArrayHelper::getValue($lastAnswer, 'survey_answer_sort', 0) + 1; 171 | } else { 172 | $pevAnswer = $answers[$after] ? $answers[$after] : null; 173 | $sort = ArrayHelper::getValue($pevAnswer, 'survey_answer_sort', 0) + 1; 174 | 175 | //moving all new answers forward 176 | SurveyAnswer::updateAll(['survey_answer_sort' => new Expression('survey_answer_sort+1')], 177 | ['AND', ['>=', 'survey_answer_sort', $sort], ['survey_answer_question_id' => $question->survey_question_id]]); 178 | } 179 | 180 | $question->link('answers', (new SurveyAnswer(['survey_answer_sort' => $sort]))); 181 | //updated model 182 | $question = $this->findModel($id); 183 | 184 | return $this->renderAjax('_form', ['question' => $question]); 185 | } 186 | 187 | public function actionDeleteAnswer($id, $answer) 188 | { 189 | $question = $this->findModel($id); 190 | $answer = $question->answers[$answer]; 191 | $answer->delete(); 192 | 193 | //updated model 194 | $question = $this->findModel($id); 195 | 196 | return $this->renderAjax('_form', ['question' => $question]); 197 | } 198 | 199 | public function actionUpdateAndClose($id) 200 | { 201 | $question = $this->findModel($id); 202 | 203 | $post = \Yii::$app->request->post(); 204 | 205 | $questionData = ArrayHelper::getValue($post, "SurveyQuestion.{$question->survey_question_id}"); 206 | if (!empty($questionData) && $question->load($questionData, '')) { 207 | $question->save(); 208 | } 209 | 210 | $answersData = ArrayHelper::getValue($post, "SurveyAnswer.{$question->survey_question_id}"); 211 | if (!empty($answersData) && Model::loadMultiple($question->answers, $answersData, '')) { 212 | foreach ($question->answers as $answer) { 213 | $answer->save(); 214 | } 215 | } 216 | 217 | return $this->renderAjax('cardView', ['question' => $question]); 218 | } 219 | 220 | 221 | protected function findModel($id) 222 | { 223 | if (($model = SurveyQuestion::findOne($id)) !== null) { 224 | return $model; 225 | } else { 226 | throw new NotFoundHttpException('The requested page does not exist.'); 227 | } 228 | } 229 | 230 | protected function findSurveyModel($id) 231 | { 232 | if (($model = Survey::findOne($id)) !== null) { 233 | return $model; 234 | } else { 235 | throw new NotFoundHttpException('The requested page does not exist.'); 236 | } 237 | } 238 | 239 | protected function findTypeModel($id) 240 | { 241 | if (($model = SurveyType::findOne($id)) !== null) { 242 | return $model; 243 | } else { 244 | throw new NotFoundHttpException('The requested page does not exist.'); 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /messages/en/survey.php: -------------------------------------------------------------------------------- 1 | 'Create new survey', 11 | ]; -------------------------------------------------------------------------------- /messages/ru/survey.php: -------------------------------------------------------------------------------- 1 | 'Добавление нового опроса', 12 | 'New Survey' => 'Новый Опрос', 13 | 'Created at' => 'Добавлен', 14 | 'Updated at' => 'Обновлен', 15 | 'Expired at' => 'Действует до', 16 | 'Question Type' => 'Тип вопроса', 17 | 'New Question' => 'Новый Вопрос', 18 | 'Add question' => 'Добавить вопрос', 19 | 'Save' => 'Сохранить', 20 | 'Can be skipped' => 'Может быть пропущен', 21 | 'Detailed description' => 'Подробное описание', 22 | 'Show detailed description' => 'Показывать подробное описание', 23 | 'Points' => 'Баллы', 24 | 'Score this question' => 'Оценивать этот вопрос', 25 | 'Type' => 'Тип', 26 | 'Description' => 'Описание', 27 | 'Answer' => 'Ответ', 28 | 'Question' => 'Вопрос', 29 | 'Enter an answer choice' => 'Введите вариант ответа', 30 | 'Comment' => 'Комментарий', 31 | 'Name' => 'Наименование', 32 | 'Closed' => 'Закрыт', 33 | 'Pinned' => 'Закреплен', 34 | 'Price' => 'Цена', 35 | 'Tags' => 'Теги', 36 | 'Current types are not compatible, all entered data will be deleted. Are you sure?' => 'Текущие типы несовместимы, все введенные данные будут удалены. Вы уверены?', 37 | 'Label' => 'Заголовок', 38 | 'Enter your answer here' => 'Введите свой ответ', 39 | 'Time to pass' => 'Время прохождения', 40 | 'Enter question name' => 'Введите вопрос', 41 | 'Were interviewed' => 'Прошли опрос', 42 | 'Respondents count' => 'Респондентов', 43 | 'Questions count' => 'Вопросов', 44 | 'Number of respondents' => 'Респондентов', 45 | 'Add respondents' => 'Добавить респондентов', 46 | 47 | 'Error' => 'Ошибка', 48 | 'Complete' => 'Завершено', 49 | 'An error has occurred' => 'Ошибка', 50 | 'Operation completed successfully' => 'Операция завершена успешно', 51 | 'Select...' => 'Выбрать', 52 | 'Done' => 'Готово', 53 | 'You must enter an answer' => 'Необходимо ввести ответ', 54 | 55 | 'Multiple choice' => 'Множественный выбор', 56 | 'One choise of list' => 'Один из списка', 57 | 'Dropdown' => 'Выпадающий список', 58 | 'Ranking' => 'Ранжирование', 59 | 'Slider' => 'Слайдер', 60 | 'Single textbox' => 'Одно текстовое поле', 61 | 'Multiple textboxes' => 'Несколько текстовых полей', 62 | 'Comment box' => 'Открытый ответ', 63 | 'Date/Time' => 'Дата/Время', 64 | 65 | 'Wallet Price' => 'В кошелек', 66 | 'Status Price' => 'В статус', 67 | ]; -------------------------------------------------------------------------------- /migrations/m181018_070730_create_table_survey.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 11 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 12 | } 13 | 14 | $this->createTable('{{%survey}}', [ 15 | 'survey_id' => $this->primaryKey()->unsigned(), 16 | 'survey_name' => $this->string(), 17 | 'survey_created_at' => $this->timestamp()->defaultExpression('CURRENT_TIMESTAMP'), 18 | 'survey_updated_at' => $this->timestamp(), 19 | 'survey_expired_at' => $this->timestamp(), 20 | 'survey_is_pinned' => $this->boolean()->defaultValue('0'), 21 | 'survey_is_closed' => $this->boolean()->defaultValue('0'), 22 | 'survey_tags' => $this->string(), 23 | 'survey_image' => $this->string(), 24 | 'survey_created_by' => $this->integer(), 25 | 'survey_wallet' => $this->integer()->unsigned(), 26 | 'survey_status' => $this->integer()->unsigned(), 27 | 'survey_descr' => $this->text(), 28 | 'survey_time_to_pass' => $this->smallInteger()->unsigned(), 29 | 'survey_badge_id' => $this->integer()->unsigned(), 30 | ], $tableOptions); 31 | 32 | $this->createIndex('fk_survey_created_by_idx', '{{%survey}}', 'survey_created_by'); 33 | } 34 | 35 | public function down() 36 | { 37 | $this->dropTable('{{%survey}}'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /migrations/m181018_070730_create_table_survey_answer.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 11 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 12 | } 13 | 14 | $this->createTable('{{%survey_answer}}', [ 15 | 'survey_answer_id' => $this->bigPrimaryKey()->unsigned(), 16 | 'survey_answer_question_id' => $this->integer()->unsigned(), 17 | 'survey_answer_name' => $this->string(), 18 | 'survey_answer_descr' => $this->text(), 19 | 'survey_answer_class' => $this->string(), 20 | 'survey_answer_comment' => $this->string(), 21 | 'survey_answer_sort' => $this->integer(), 22 | 'survey_answer_points' => $this->integer()->defaultValue('0'), 23 | 'survey_answer_show_descr' => $this->boolean()->defaultValue('0'), 24 | ], $tableOptions); 25 | 26 | $this->createIndex('fk_survey_answer_to_question_idx', '{{%survey_answer}}', 'survey_answer_question_id'); 27 | } 28 | 29 | public function down() 30 | { 31 | $this->dropTable('{{%survey_answer}}'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /migrations/m181018_070730_create_table_survey_question.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 11 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 12 | } 13 | 14 | $this->createTable('{{%survey_question}}', [ 15 | 'survey_question_id' => $this->primaryKey()->unsigned(), 16 | 'survey_question_name' => $this->string(), 17 | 'survey_question_descr' => $this->text(), 18 | 'survey_question_type' => $this->tinyInteger()->unsigned(), 19 | 'survey_question_survey_id' => $this->integer()->unsigned(), 20 | 'survey_question_can_skip' => $this->boolean()->defaultValue('0'), 21 | 'survey_question_show_descr' => $this->boolean()->defaultValue('0'), 22 | 'survey_question_is_scorable' => $this->boolean()->defaultValue('0'), 23 | ], $tableOptions); 24 | 25 | $this->createIndex('fk_survey_question_to_survey_idx', '{{%survey_question}}', 'survey_question_survey_id'); 26 | $this->createIndex('fk_survey_question_to_type_idx', '{{%survey_question}}', 'survey_question_type'); 27 | } 28 | 29 | public function down() 30 | { 31 | $this->dropTable('{{%survey_question}}'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /migrations/m181018_070730_create_table_survey_stat.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 11 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 12 | } 13 | 14 | $this->createTable('{{%survey_stat}}', [ 15 | 'survey_stat_id' => $this->primaryKey()->unsigned(), 16 | 'survey_stat_survey_id' => $this->integer()->unsigned(), 17 | 'survey_stat_user_id' => $this->integer(), 18 | 'survey_stat_assigned_at' => $this->timestamp(), 19 | 'survey_stat_started_at' => $this->timestamp(), 20 | 'survey_stat_updated_at' => $this->timestamp(), 21 | 'survey_stat_ended_at' => $this->timestamp(), 22 | 'survey_stat_ip' => $this->string(), 23 | 'survey_stat_is_done' => $this->boolean()->defaultValue('0'), 24 | 'survey_stat_hash' => $this->char(32), 25 | ], $tableOptions); 26 | 27 | $this->createIndex('fk_sas_user_idx', '{{%survey_stat}}', 'survey_stat_user_id'); 28 | $this->createIndex('survey_stat_hash_UNIQUE', '{{%survey_stat}}', 'survey_stat_hash', true); 29 | $this->createIndex('fk_stat_to_survey_idx', '{{%survey_stat}}', 'survey_stat_survey_id'); 30 | } 31 | 32 | public function down() 33 | { 34 | $this->dropTable('{{%survey_stat}}'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /migrations/m181018_070730_create_table_survey_type.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 11 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 12 | } 13 | 14 | $this->createTable('{{%survey_type}}', [ 15 | 'survey_type_id' => $this->tinyInteger()->unsigned()->notNull()->append('AUTO_INCREMENT PRIMARY KEY'), 16 | 'survey_type_name' => $this->string(), 17 | 'survey_type_descr' => $this->string(), 18 | ], $tableOptions); 19 | 20 | $this->batchInsert('{{%survey_type}}', ['survey_type_name', 'survey_type_descr'], [ 21 | ['Multiple choice', 'Ask your respondent to choose multiple answers from your list of answer choices.'], 22 | ['One choise of list', 'Ask your respondent to choose one answer from your list of answer choices.'], 23 | ['Dropdown', 'Provide a dropdown list of answer choices for respondents to choose from.'], 24 | ['Ranking', 'Ask respondents to rank a list of options in the order they prefer using numeric dropdown menus.'], 25 | ['Slider', 'Ask respondents to rate an item or question by dragging an interactive slider.'], 26 | ['Single textbox', 'Add a single textbox to your survey when you want respondents to write in a short text or numerical answer to your question.'], 27 | ['Multiple textboxes', 'Add multiple textboxes to your survey when you want respondents to write in more than one short text or numerical answer to your question.'], 28 | ['Comment box', 'Use the comment or essay box to collect open-ended, written feedback from respondents.'], 29 | ['Date/Time', 'Ask respondents to enter a specific date and/or time.'], 30 | ['Calendar', 'Ask respondents to choose better date/time for a meeting.'] 31 | ]); 32 | 33 | } 34 | 35 | public function down() 36 | { 37 | $this->dropTable('{{%survey_type}}'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /migrations/m181018_070730_create_table_survey_user_answer.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 11 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 12 | } 13 | 14 | $this->createTable('{{%survey_user_answer}}', [ 15 | 'survey_user_answer_id' => $this->primaryKey()->unsigned(), 16 | 'survey_user_answer_user_id' => $this->integer(), 17 | 'survey_user_answer_survey_id' => $this->integer()->unsigned(), 18 | 'survey_user_answer_question_id' => $this->integer()->unsigned(), 19 | 'survey_user_answer_answer_id' => $this->bigInteger()->unsigned(), 20 | 'survey_user_answer_value' => $this->string(), 21 | 'survey_user_answer_text' => $this->text(), 22 | ], $tableOptions); 23 | 24 | $this->createIndex('fk_survey_user_answer_answer_idx', '{{%survey_user_answer}}', 'survey_user_answer_answer_id'); 25 | $this->createIndex('fk_survey_user_answer_user_idx', '{{%survey_user_answer}}', 'survey_user_answer_user_id'); 26 | $this->createIndex('idx_answer_value', '{{%survey_user_answer}}', ['survey_user_answer_answer_id', 'survey_user_answer_value']); 27 | $this->createIndex('idx_question_value', '{{%survey_user_answer}}', ['survey_user_answer_question_id', 'survey_user_answer_value']); 28 | $this->createIndex('ff_idx', '{{%survey_user_answer}}', 'survey_user_answer_survey_id'); 29 | $this->createIndex('fk_survey_user_answer_question_idx', '{{%survey_user_answer}}', 'survey_user_answer_question_id'); 30 | $this->createIndex('idx_survey_user_answer_value', '{{%survey_user_answer}}', 'survey_user_answer_value'); 31 | } 32 | 33 | public function down() 34 | { 35 | $this->dropTable('{{%survey_user_answer}}'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /migrations/m181018_070730_foreign_keys.php: -------------------------------------------------------------------------------- 1 | addForeignKey('fk_survey_answer_to_question', '{{%survey_answer}}', 'survey_answer_question_id', '{{%survey_question}}', 'survey_question_id', 'CASCADE', 'CASCADE'); 11 | $this->addForeignKey('fk_survey_question_to_survey', '{{%survey_question}}', 'survey_question_survey_id', '{{%survey}}', 'survey_id', 'CASCADE', 'CASCADE'); 12 | $this->addForeignKey('fk_survey_question_to_type', '{{%survey_question}}', 'survey_question_type', '{{%survey_type}}', 'survey_type_id', 'NO ACTION', 'CASCADE'); 13 | $this->addForeignKey('fk_stat_to_survey', '{{%survey_stat}}', 'survey_stat_survey_id', '{{%survey}}', 'survey_id', 'CASCADE', 'CASCADE'); 14 | $this->addForeignKey('fk_survey_user_answer_answer', '{{%survey_user_answer}}', 'survey_user_answer_answer_id', '{{%survey_answer}}', 'survey_answer_id', 'CASCADE', 'CASCADE'); 15 | $this->addForeignKey('fk_survey_user_answer_question', '{{%survey_user_answer}}', 'survey_user_answer_question_id', '{{%survey_question}}', 'survey_question_id', 'CASCADE', 'CASCADE'); 16 | $this->addForeignKey('fk_survey_user_answer_survey', '{{%survey_user_answer}}', 'survey_user_answer_survey_id', '{{%survey}}', 'survey_id', 'CASCADE', 'CASCADE'); 17 | 18 | try { 19 | $this->addForeignKey('fk_survey_created_by', '{{%survey}}', 'survey_created_by', '{{%user}}', 'id', 'SET NULL', 'CASCADE'); 20 | $this->addForeignKey('fk_stat_to_user', '{{%survey_stat}}', 'survey_stat_user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE'); 21 | $this->addForeignKey('fk_survey_user_answer_user', '{{%survey_user_answer}}', 'survey_user_answer_user_id', '{{%user}}', 'id', 'SET NULL', 'SET NULL'); 22 | } catch (\yii\db\Exception $e) { 23 | } 24 | 25 | } 26 | 27 | public function down() 28 | { 29 | 30 | $this->dropForeignKey('fk_survey_answer_to_question', '{{%survey_answer}}'); 31 | $this->dropForeignKey('fk_survey_question_to_survey', '{{%survey_question}}'); 32 | $this->dropForeignKey('fk_survey_question_to_type', '{{%survey_question}}'); 33 | $this->dropForeignKey('fk_stat_to_survey', '{{%survey_stat}}'); 34 | $this->dropForeignKey('fk_survey_user_answer_answer', '{{%survey_user_answer}}'); 35 | $this->dropForeignKey('fk_survey_user_answer_question', '{{%survey_user_answer}}'); 36 | $this->dropForeignKey('fk_survey_user_answer_survey', '{{%survey_user_answer}}'); 37 | 38 | try { 39 | $this->dropForeignKey('fk_survey_created_by', '{{%survey}}'); 40 | $this->dropForeignKey('fk_stat_to_user', '{{%survey_stat}}'); 41 | $this->dropForeignKey('fk_survey_user_answer_user', '{{%survey_user_answer}}'); 42 | } catch (\yii\db\Exception $e) { 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /migrations/m190918_224430_private_survey.php: -------------------------------------------------------------------------------- 1 | alterColumn('{{%survey}}', 'survey_updated_at', $this->timestamp()->null()->defaultValue(null)); 10 | $this->alterColumn('{{%survey}}', 'survey_expired_at', $this->timestamp()->null()->defaultValue(null)); 11 | 12 | $this->addColumn('{{%survey}}', 'survey_is_private', $this->boolean()->notNull()->defaultValue(false)); 13 | $this->addColumn('{{%survey}}', 'survey_is_visible', $this->boolean()->notNull()->defaultValue(false)); 14 | 15 | $this->createTable('{{%survey_restricted_user}}', [ 16 | 'survey_restricted_user_id' => $this->primaryKey()->unsigned(), 17 | 'survey_restricted_user_survey_id' => $this->integer()->unsigned()->notNull(), 18 | 'survey_restricted_user_user_id' => $this->integer()->notNull(), 19 | ]); 20 | 21 | $this->addForeignKey('fk_survey_restricted_user_to_survey', '{{%survey_restricted_user}}', 'survey_restricted_user_survey_id', '{{%survey}}', 'survey_id', 'CASCADE', 'CASCADE'); 22 | 23 | try { 24 | $this->addForeignKey('fk_survey_restricted_user_to_user', '{{%survey_restricted_user}}', 'survey_restricted_user_user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE'); 25 | } catch (\yii\db\Exception $e) { 26 | } 27 | } 28 | 29 | public function down() 30 | { 31 | $this->dropForeignKey('fk_survey_restricted_user_to_survey', '{{%survey_restricted_user}}'); 32 | 33 | try { 34 | $this->dropForeignKey('fk_survey_restricted_user_to_user', '{{%survey_restricted_user}}'); 35 | } catch (\yii\db\Exception $e) { 36 | } 37 | 38 | $this->dropTable('{{%survey_restricted_user}}'); 39 | 40 | $this->dropColumn('{{%survey}}', 'survey_is_private'); 41 | $this->dropColumn('{{%survey}}', 'survey_is_visible'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /models/Survey.php: -------------------------------------------------------------------------------- 1 | survey_created_by = \Yii::$app->user->getId(); 61 | } 62 | return parent::beforeSave($insert); 63 | } 64 | 65 | /** 66 | * @inheritdoc 67 | */ 68 | public function rules() 69 | { 70 | return [ 71 | [['survey_created_at', 'survey_updated_at', 'survey_expired_at'], 'safe'], 72 | [['survey_is_pinned', 'survey_is_closed', 'survey_is_private', 'survey_is_visible'], 'boolean'], 73 | [['survey_name'], 'string', 'max' => 45], 74 | [['survey_descr'], 'string'], 75 | [['survey_tags', 'survey_image'], 'string', 'max' => 255], 76 | [['survey_name'], 'required'], 77 | [['survey_wallet', 'survey_status', 'survey_created_by', 'survey_time_to_pass', 'survey_badge_id'], 'integer'], 78 | [['imageFile'], 'file', 'mimeTypes' => 'image/jpeg, image/png', 'maxSize' => 5000000] 79 | ]; 80 | } 81 | 82 | /** 83 | * @inheritdoc 84 | */ 85 | public function attributeLabels() 86 | { 87 | return [ 88 | 'survey_id' => Yii::t('survey', 'Survey ID'), 89 | 'survey_name' => Yii::t('survey', 'Name'), 90 | 'survey_created_at' => Yii::t('survey', 'Created at'), 91 | 'survey_updated_at' => Yii::t('survey', 'Updated at'), 92 | 'survey_expired_at' => Yii::t('survey', 'Expired at'), 93 | 'survey_is_pinned' => Yii::t('survey', 'Pinned'), 94 | 'survey_is_closed' => Yii::t('survey', 'Closed'), 95 | 'survey_is_private' => Yii::t('survey', 'Private'), 96 | 'survey_is_visible' => Yii::t('survey', 'Visible'), 97 | 'survey_wallet' => Yii::t('survey', 'Price'), 98 | 'survey_tags' => Yii::t('survey', 'Tags'), 99 | 'survey_descr' => Yii::t('survey', 'Description'), 100 | 'survey_time_to_pass' => Yii::t('survey', 'Time to pass'), 101 | 'restrictedUserIds' => Yii::t('survey', 'Restricted users'), 102 | 'imageFile' => '', 103 | ]; 104 | } 105 | 106 | /** 107 | * @return \yii\db\ActiveQuery 108 | */ 109 | public function getSurveyUserAnswers() 110 | { 111 | return $this->hasOne(SurveyUserAnswer::class, ['survey_user_answer_survey_id' => 'survey_id']); 112 | } 113 | 114 | /** 115 | * @return \yii\db\ActiveQuery 116 | */ 117 | public function getQuestions() 118 | { 119 | return $this->hasMany(SurveyQuestion::class, ['survey_question_survey_id' => 'survey_id']); 120 | } 121 | 122 | /** 123 | * @return \yii\db\ActiveQuery 124 | */ 125 | public function getStats() 126 | { 127 | return $this->hasMany(SurveyStat::class, ['survey_stat_survey_id' => 'survey_id']); 128 | } 129 | 130 | /** 131 | * @return \yii\db\ActiveQuery 132 | */ 133 | public function getRestrictedUsers() 134 | { 135 | return $this->hasMany(Yii::$app->user->identityClass, ['id' => 'survey_restricted_user_user_id']) 136 | ->viaTable('survey_restricted_user', ['survey_restricted_user_survey_id' => 'survey_id']); 137 | } 138 | 139 | public function getStatus() 140 | { 141 | if (isset($this->survey_expired_at) && strtotime($this->survey_expired_at) < time()) { 142 | $status = 'expired'; 143 | } else { 144 | $status = $this->survey_is_closed ? 'closed' : 'active'; 145 | } 146 | return $status; 147 | } 148 | 149 | public function setQuestions($val) 150 | { 151 | return $this->questions = $val; 152 | } 153 | 154 | public function getRespondentsCount() 155 | { 156 | return SurveyStat::find()->where(['survey_stat_survey_id' => $this->survey_id])->count(); 157 | } 158 | 159 | public function getCompletedRespondentsCount() 160 | { 161 | return SurveyStat::find()->where(['survey_stat_survey_id' => $this->survey_id]) 162 | ->andWhere(['survey_stat_is_done' => true]) 163 | ->count(); 164 | } 165 | 166 | static function getDropdownList() 167 | { 168 | return ArrayHelper::map(self::find() 169 | ->leftJoin('survey_restricted_user', 'survey_id = survey_restricted_user_survey_id') 170 | ->where(new AndCondition([ 171 | ['survey_is_visible' => 1], 172 | new OrCondition([ 173 | ['>', 'survey_expired_at', new Expression('NOW()')], 174 | ['survey_expired_at' => null] 175 | ]), 176 | new OrCondition([ 177 | ['survey_is_private' => 0], 178 | ['survey_restricted_user_user_id' => \Yii::$app->user->id] 179 | ]) 180 | ])) 181 | ->orderBy(['survey_created_at' => SORT_ASC]) 182 | ->asArray()->all(), 'survey_id', 'survey_name'); 183 | } 184 | 185 | /** 186 | * @return string 187 | */ 188 | public function getImage() 189 | { 190 | $file = !empty($this->survey_image) ? $this->survey_image : null; 191 | 192 | if (empty($file)) { 193 | return null; 194 | } 195 | $module = \Yii::$app->getModule('survey'); 196 | $basepath = $module->params['uploadsUrl']; 197 | $path = $basepath . '/' . $this->survey_image; 198 | 199 | return $path; 200 | } 201 | 202 | public function getAuthorName() 203 | { 204 | try { 205 | $userClass = \Yii::$app->user->identityClass; 206 | $author = $userClass::findOne($this->survey_created_by); 207 | if ($author) { 208 | return $author->username; 209 | } else { 210 | return null; 211 | } 212 | } catch (\Throwable $e) { 213 | return 'undefined'; 214 | } 215 | } 216 | 217 | public static function assignRestrictedUser($userId, $surveyId) { 218 | $survey = self::findOne($surveyId); 219 | $userClass = \Yii::$app->user->identityClass; 220 | $survey->link('restrictedUsers', $userClass::findOne($userId)); 221 | return true; 222 | } 223 | 224 | public static function unassignRestrictedUser($userId, $surveyId) { 225 | $survey = self::findOne($surveyId); 226 | $userClass = \Yii::$app->user->identityClass; 227 | $survey->unlink('restrictedUsers', $userClass::findOne($userId), true); 228 | return true; 229 | } 230 | 231 | public function getRestrictedUsersCount() 232 | { 233 | return self::find() 234 | ->innerJoin('survey_restricted_user', 'survey_id = survey_restricted_user_survey_id') 235 | ->where(['survey_id' => $this->survey_id]) 236 | ->count(); 237 | } 238 | 239 | public function getRestrictedUserIds() { 240 | return ArrayHelper::map($this->restrictedUsers, 'id', 'id'); 241 | } 242 | 243 | public function getRestrictedUserNames() { 244 | return ArrayHelper::map($this->restrictedUsers, 'id', 'fullname'); 245 | } 246 | 247 | public function isAccessibleBy($userId) { 248 | return ($this->survey_is_visible && (!$this->survey_is_private || in_array($userId, $this->restrictedUserIds))); 249 | } 250 | 251 | public function getIsAccessibleByCurrentUser() { 252 | return $this->isAccessibleBy(\Yii::$app->user->id); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /models/SurveyAnswer.php: -------------------------------------------------------------------------------- 1 | 'intval'], 44 | [['survey_answer_show_descr'], 'boolean'], 45 | [['survey_answer_show_descr'], 'filter', 'filter' => 'boolval'], 46 | [['survey_answer_name'], 'string', 'max' => 100], 47 | [['survey_answer_name'], 'required'], 48 | [['survey_answer_class', 'survey_answer_comment'], 'string', 'max' => 255], 49 | [['survey_answer_question_id'], 'exist', 'skipOnError' => true, 'targetClass' => SurveyQuestion::class, 'targetAttribute' => ['survey_answer_question_id' => 'survey_question_id']], 50 | ]; 51 | } 52 | 53 | 54 | 55 | public function afterDelete() 56 | { 57 | $question = $this->question; 58 | if (!empty($question)) { 59 | $answersCount = $question->getAnswers()->count(); 60 | if ($answersCount == 0) { 61 | //prevent deleting last answer 62 | $question->link('answers', (new SurveyAnswer(['survey_answer_sort' => 0]))); 63 | } 64 | } 65 | 66 | return parent::afterDelete(); 67 | } 68 | 69 | /** 70 | * @inheritdoc 71 | */ 72 | public function attributeLabels() 73 | { 74 | return [ 75 | 'survey_answer_id' => Yii::t('survey', 'Answer ID'), 76 | 'survey_answer_name' => Yii::t('survey', 'Answer'), 77 | 'survey_answer_descr' => Yii::t('survey', 'Detailed description'), 78 | 'survey_answer_show_descr' => Yii::t('survey', 'Show detailed description'), 79 | 'survey_answer_class' => Yii::t('survey', 'Class'), 80 | 'survey_answer_comment' => Yii::t('survey', 'Comment'), 81 | 'survey_answer_question_id' => Yii::t('survey', 'Question ID'), 82 | 'survey_answer_points' => Yii::t('survey', 'Points'), 83 | ]; 84 | } 85 | 86 | /** 87 | * @return \yii\db\ActiveQuery 88 | */ 89 | public function getQuestion() 90 | { 91 | return $this->hasOne(SurveyQuestion::class, ['survey_question_id' => 'survey_answer_question_id']); 92 | } 93 | 94 | /** 95 | * @return \yii\db\ActiveQuery 96 | */ 97 | public function getUserAnswers() 98 | { 99 | return $this->hasMany(SurveyUserAnswer::class, ['survey_user_answer_answer_id' => 'survey_answer_id']); 100 | } 101 | 102 | /** 103 | * Returns the total number of users voted for this answer 104 | * 105 | * @return int 106 | */ 107 | public function getTotalUserAnswersCount() 108 | { 109 | switch ($this->question->survey_question_type){ 110 | case SurveyType::TYPE_MULTIPLE: 111 | $result = SurveyUserAnswer::find()->where(['survey_user_answer_answer_id' => $this->survey_answer_id]) 112 | ->andWhere(['survey_user_answer_value' => 1]) 113 | ->count(); 114 | break; 115 | case SurveyType::TYPE_ONE_OF_LIST: 116 | case SurveyType::TYPE_DROPDOWN: 117 | $result = SurveyUserAnswer::find()->andWhere(['survey_user_answer_value' => $this->survey_answer_id]) 118 | ->count(); 119 | break; 120 | case SurveyType::TYPE_RANKING: 121 | 122 | $result = (new Query()) 123 | ->from(SurveyUserAnswer::tableName()) 124 | ->addSelect(['AVG(survey_user_answer_value) average']) 125 | ->where(['survey_user_answer_answer_id' => $this->survey_answer_id]) 126 | ->andWhere(['>', 'survey_user_answer_value', 0]) 127 | ->groupBy(['survey_user_answer_answer_id'])->scalar(); 128 | break; 129 | case SurveyType::TYPE_SLIDER: 130 | $result = (new Query()) 131 | ->from(SurveyUserAnswer::tableName()) 132 | ->addSelect(['AVG(survey_user_answer_value) average']) 133 | ->andWhere(['survey_user_answer_question_id' => $this->question->survey_question_id]) 134 | ->andWhere(['is not', 'survey_user_answer_value', null]) 135 | ->groupBy(['survey_user_answer_question_id'])->scalar(); 136 | break; 137 | default: 138 | $result = 0; 139 | break; 140 | } 141 | 142 | return $result; 143 | 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /models/SurveyQuestion.php: -------------------------------------------------------------------------------- 1 | userAnswers; 42 | if (!$question->survey_question_can_skip){ 43 | if ($question->survey_question_type === SurveyType::TYPE_MULTIPLE){ 44 | $answerValues = ArrayHelper::getColumn($userAnswers, 'survey_user_answer_value'); 45 | if (!in_array("1", $answerValues)){ 46 | $answer = (array)$question->userAnswers; 47 | if(!empty($answer)) { 48 | end($answer)->addError('survey_user_answer_value', \Yii::t('survey', 'You must enter an answer')); 49 | } 50 | } 51 | } 52 | } 53 | return true; 54 | } 55 | 56 | public function changeDefaultValuesOnTypeChange(){ 57 | /** @var SurveyQuestion $question */ 58 | $question = $this; 59 | $oldType = $question->getOldAttribute('survey_question_type'); 60 | $newType = $question->getAttribute('survey_question_type'); 61 | if ($oldType === $newType){ 62 | return true; 63 | } 64 | 65 | if ($newType === SurveyType::TYPE_SLIDER){ 66 | $question->unlinkAll('answers', true); 67 | for ($i = 1; $i <= 2; ++$i) { 68 | $answer = new SurveyAnswer(); 69 | $answer->survey_answer_sort = $i; 70 | $answer->survey_answer_name = ($i === 1) ? 0 : 100; 71 | $question->link('answers', $answer); 72 | } 73 | }else if($oldType === SurveyType::TYPE_SLIDER){ 74 | $question->unlinkAll('answers', true); 75 | for ($i = 1; $i <= 2; ++$i) { 76 | $answer = new SurveyAnswer(); 77 | $answer->survey_answer_sort = $i; 78 | $question->link('answers', $answer); 79 | } 80 | } 81 | 82 | return true; 83 | } 84 | 85 | /** 86 | * @inheritdoc 87 | */ 88 | public function rules() 89 | { 90 | return [ 91 | [['survey_question_descr'], 'string'], 92 | [['survey_question_type', 'survey_question_survey_id'], 'integer'], 93 | [['survey_question_type'], 'filter', 'filter' => 'intval'], 94 | [['survey_question_can_skip', 'survey_question_show_descr', 'survey_question_is_scorable'], 'boolean'], 95 | [['survey_question_can_skip', 'survey_question_show_descr', 'survey_question_is_scorable'], 'filter', 'filter' => 'boolval'], 96 | [['survey_question_name'], 'string', 'max' => 130], 97 | [['survey_question_name'], 'required'], 98 | [['survey_question_survey_id'], 'exist', 'skipOnError' => true, 'targetClass' => Survey::class, 'targetAttribute' => ['survey_question_survey_id' => 'survey_id']], 99 | [['survey_question_type'], 'exist', 'skipOnError' => true, 'targetClass' => SurveyType::class, 'targetAttribute' => ['survey_question_type' => 'survey_type_id']], 100 | ]; 101 | } 102 | 103 | public function beforeSave($insert) 104 | { 105 | //scorable questions 106 | if (!$insert && !in_array($this->survey_question_type, [ 107 | SurveyType::TYPE_MULTIPLE, 108 | SurveyType::TYPE_ONE_OF_LIST, 109 | SurveyType::TYPE_DROPDOWN 110 | ])) { 111 | if ($this->survey_question_is_scorable){ 112 | $this->survey_question_is_scorable = false; 113 | } 114 | } 115 | return parent::beforeSave($insert); // TODO: Change the autogenerated stub 116 | } 117 | 118 | public function loadDefaultValues($skipIfSet = true) 119 | { 120 | parent::loadDefaultValues($skipIfSet); 121 | $this->survey_question_type = SurveyType::TYPE_MULTIPLE; //multiple choice 122 | return $this; 123 | } 124 | 125 | /** 126 | * @inheritdoc 127 | */ 128 | public function attributeLabels() 129 | { 130 | return [ 131 | 'survey_question_id' => Yii::t('survey', 'Question ID'), 132 | 'survey_question_name' => Yii::t('survey', 'Survey Question Name'), 133 | 'survey_question_descr' => Yii::t('survey', 'Detailed description'), 134 | 'survey_question_type' => Yii::t('survey', 'Question Type'), 135 | 'survey_question_survey_id' => Yii::t('survey', 'Survey ID'), 136 | 'survey_question_can_skip' => Yii::t('survey', 'Can be skipped'), 137 | 'survey_question_show_descr' => Yii::t('survey', 'Show detailed description'), 138 | 'survey_question_is_scorable' => Yii::t('survey', 'Score this question'), 139 | ]; 140 | } 141 | 142 | /** 143 | * @return \yii\db\ActiveQuery 144 | */ 145 | public function getAnswers() 146 | { 147 | return $this->hasMany(SurveyAnswer::class, ['survey_answer_question_id' => 'survey_question_id']) 148 | ->orderBy(['survey_answer_sort' => SORT_ASC, 'survey_answer_id' => SORT_ASC]); 149 | } 150 | 151 | /** 152 | * @return \yii\db\ActiveQuery 153 | */ 154 | public function getSurvey() 155 | { 156 | return $this->hasOne(Survey::class, ['survey_id' => 'survey_question_survey_id']); 157 | } 158 | 159 | /** 160 | * @return \yii\db\ActiveQuery 161 | */ 162 | public function getQuestionType() 163 | { 164 | return $this->hasOne(SurveyType::class, ['survey_type_id' => 'survey_question_type']); 165 | } 166 | 167 | /** 168 | * @return \yii\db\ActiveQuery 169 | */ 170 | public function getUserAnswers() 171 | { 172 | return $this->hasMany(SurveyUserAnswer::class, ['survey_user_answer_question_id' => 'survey_question_id']) 173 | ->andOnCondition(['survey_user_answer_user_id' => \Yii::$app->user->getId()]) 174 | ->indexBy('survey_user_answer_answer_id'); 175 | } 176 | 177 | /** 178 | * Returns the total number of users voted for this answer 179 | * 180 | * @return int 181 | */ 182 | public function getTotalUserAnswersCount() 183 | { 184 | switch ($this->survey_question_type){ 185 | case SurveyType::TYPE_MULTIPLE: 186 | $result = SurveyUserAnswer::find()->where(['survey_user_answer_question_id' => $this->survey_question_id]) 187 | ->andWhere(['survey_user_answer_value' => 1]) 188 | ->count(); 189 | break; 190 | case SurveyType::TYPE_ONE_OF_LIST: 191 | case SurveyType::TYPE_DROPDOWN: 192 | $result = SurveyUserAnswer::find()->where(['survey_user_answer_question_id' => $this->survey_question_id]) 193 | ->andWhere(['>', 'survey_user_answer_value', 0]) 194 | ->count(); 195 | break; 196 | default: 197 | $result = 0; 198 | break; 199 | } 200 | 201 | return $result; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /models/SurveyStat.php: -------------------------------------------------------------------------------- 1 | survey_stat_hash = self::generateHash($this->survey_stat_survey_id, $this->survey_stat_user_id); 47 | } 48 | return parent::beforeSave($insert); 49 | } 50 | 51 | public function afterSave($insert, $changedAttributes) 52 | { 53 | parent::afterSave($insert, $changedAttributes); 54 | if ($insert){ 55 | \Yii::$app->trigger(self::EVENT_SURVEY_HAS_BEEN_ASSIGN, new Event(['sender' => $this])); 56 | } 57 | 58 | if (isset($changedAttributes['survey_stat_is_done']) && $changedAttributes['survey_stat_is_done'] === false){ 59 | Event::trigger(self::class, self::EVENT_SURVEY_AFTER_COMPLETE, new Event(['sender' => $this])); 60 | \Yii::$app->trigger(self::EVENT_SURVEY_AFTER_COMPLETE, new Event(['sender' => $this])); 61 | } 62 | } 63 | 64 | /** 65 | * @param $survey_stat_survey_id 66 | * @param $survey_stat_user_id 67 | * @return string 68 | */ 69 | static function generateHash($survey_stat_survey_id, $survey_stat_user_id){ 70 | return md5($survey_stat_survey_id . $survey_stat_user_id); 71 | } 72 | 73 | public function behaviors() 74 | { 75 | return [ 76 | [ 77 | 'class' => TimestampBehavior::class, 78 | 'attributes' => [ 79 | BaseActiveRecord::EVENT_BEFORE_INSERT => ['survey_stat_assigned_at'], 80 | BaseActiveRecord::EVENT_BEFORE_UPDATE => ['survey_stat_updated_at'], 81 | ], 82 | 'createdAtAttribute' => 'survey_stat_assigned_at', 83 | 'updatedAtAttribute' => 'survey_stat_updated_at', 84 | 'skipUpdateOnClean' => true, 85 | 'value' => new Expression('NOW()'), 86 | ], 87 | ]; 88 | } 89 | 90 | /** 91 | * @inheritdoc 92 | */ 93 | public function rules() 94 | { 95 | return [ 96 | [['survey_stat_survey_id', 'survey_stat_user_id', 'survey_stat_hash'], 'required'], 97 | [['survey_stat_survey_id', 'survey_stat_user_id'], 'integer'], 98 | [['survey_stat_assigned_at', 'survey_stat_started_at', 'survey_stat_updated_at', 'survey_stat_ended_at'], 'safe'], 99 | [['survey_stat_is_done'], 'boolean'], 100 | [['survey_stat_ip'], 'string', 'max' => 45], 101 | [['survey_stat_hash'], 'string', 'max' => 32], 102 | [['survey_stat_survey_id'], 'exist', 'skipOnError' => true, 'targetClass' => Survey::class, 'targetAttribute' => ['survey_stat_survey_id' => 'survey_id']], 103 | [['survey_stat_user_id'], 'exist', 'skipOnError' => true, 'targetClass' => \Yii::$app->user->identityClass, 'targetAttribute' => ['survey_stat_user_id' => 'id']], 104 | ]; 105 | } 106 | 107 | /** 108 | * @inheritdoc 109 | */ 110 | public function attributeLabels() 111 | { 112 | return [ 113 | 'survey_stat_id' => Yii::t('survey', 'Survey Stat ID'), 114 | 'survey_stat_survey_id' => Yii::t('survey', 'Survey Stat Survey ID'), 115 | 'survey_stat_user_id' => Yii::t('survey', 'Survey Stat User ID'), 116 | 'survey_stat_assigned_at' => Yii::t('survey', 'Survey Stat Assigned At'), 117 | 'survey_stat_started_at' => Yii::t('survey', 'Survey Stat Started At'), 118 | 'survey_stat_updated_at' => Yii::t('survey', 'Survey Stat Updated At'), 119 | 'survey_stat_ended_at' => Yii::t('survey', 'Survey Stat Ended At'), 120 | 'survey_stat_ip' => Yii::t('survey', 'Survey Stat Ip'), 121 | 'survey_stat_is_done' => Yii::t('survey', 'Survey Stat Is Done'), 122 | ]; 123 | } 124 | 125 | /** 126 | * @return \yii\db\ActiveQuery 127 | */ 128 | public function getSurvey() 129 | { 130 | return $this->hasOne(Survey::class, ['survey_id' => 'survey_stat_survey_id']); 131 | } 132 | 133 | /** 134 | * @return \yii\db\ActiveQuery 135 | */ 136 | public function getUser() 137 | { 138 | $userClass = \Yii::$app->user->identityClass; 139 | return $this->hasOne($userClass, ['id' => 'survey_stat_user_id']); 140 | } 141 | 142 | /** 143 | * @param $userId 144 | * @param $surveyId 145 | * @return bool 146 | * @throws UserException 147 | */ 148 | static function assignUser($userId, $surveyId){ 149 | 150 | $user = Survey::findOne($surveyId); 151 | if (!$user) { 152 | throw new UserException('survey does not exist'); 153 | } 154 | 155 | /** @var \app\modules\user\models\User $User */ 156 | $User = \Yii::$app->user->identityClass; 157 | $user = $User::findOne($userId); 158 | if (!$user) { 159 | throw new UserException('user does not exist'); 160 | } 161 | 162 | $isAssigned = SurveyStat::find()->where(['survey_stat_survey_id' => $surveyId]) 163 | ->andWhere(['survey_stat_user_id' => $userId])->count(); 164 | if ($isAssigned){ 165 | throw new UserException('user already assigned', 1001); 166 | } 167 | 168 | $surveyStat = new SurveyStat(); 169 | $surveyStat->survey_stat_user_id = $userId; 170 | $surveyStat->survey_stat_survey_id = $surveyId; 171 | if ($surveyStat->save(false)){ 172 | 173 | return true; 174 | }else { 175 | return false; 176 | } 177 | } 178 | 179 | static function unassignUser($userId, $surveyId){ 180 | 181 | $user = Survey::findOne($surveyId); 182 | if (!$user) { 183 | throw new UserException('survey does not exist'); 184 | } 185 | 186 | /** @var \app\modules\user\models\User $User */ 187 | $User = \Yii::$app->user->identityClass; 188 | $user = $User::findOne($userId); 189 | if (!$user) { 190 | throw new UserException('user does not exist'); 191 | } 192 | 193 | return SurveyStat::deleteAll(['survey_stat_survey_id' => $surveyId, 'survey_stat_user_id' => $userId]); 194 | } 195 | 196 | /** 197 | * @param $userId 198 | * @param $surveyId 199 | * @return array|null|SurveyStat 200 | * @throws UserException 201 | */ 202 | static function getAssignedUserStat($userId, $surveyId){ 203 | 204 | $user = Survey::findOne($surveyId); 205 | if (!$user) { 206 | throw new UserException('survey does not exist'); 207 | } 208 | 209 | /** @var \app\modules\user\models\User $User */ 210 | $User = \Yii::$app->user->identityClass; 211 | $user = $User::findOne($userId); 212 | if (!$user) { 213 | throw new UserException('user does not exist'); 214 | } 215 | 216 | $result = SurveyStat::find()->where(['survey_stat_survey_id' => $surveyId]) 217 | ->andWhere(['survey_stat_user_id' => $userId])->one(); 218 | 219 | return $result; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /models/SurveyType.php: -------------------------------------------------------------------------------- 1 | 45], 45 | [['survey_type_descr'], 'string', 'max' => 255], 46 | ]; 47 | } 48 | 49 | /** 50 | * @inheritdoc 51 | */ 52 | public function attributeLabels() 53 | { 54 | return [ 55 | 'survey_type_id' => Yii::t('survey', 'Survey Type ID'), 56 | 'survey_type_name' => Yii::t('survey', 'Type'), 57 | 'survey_type_descr' => Yii::t('survey', 'Description'), 58 | ]; 59 | } 60 | 61 | public static function getDropdownList() 62 | { 63 | return ArrayHelper::map(SurveyType::find() 64 | ->asArray()->all(), 'survey_type_id', function($model){ 65 | return \Yii::t('survey', $model['survey_type_name']); 66 | }); 67 | } 68 | 69 | /** 70 | * @return \yii\db\ActiveQuery 71 | */ 72 | public function getSurveyQuestions() 73 | { 74 | return $this->hasMany(SurveyQuestion::class, ['survey_question_type' => 'survey_type_id']); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /models/SurveyUserAnswer.php: -------------------------------------------------------------------------------- 1 | 255], 42 | [['survey_user_answer_text'], 'string'], 43 | 44 | [['survey_user_answer_value'], 'required', 'when' => function($model){ 45 | /** @var $model SurveyUserAnswer */ 46 | return ($model->question->survey_question_can_skip == false && $model->question->survey_question_type !== SurveyType::TYPE_COMMENT_BOX); 47 | }, 'message' => \Yii::t('survey', 'You must enter an answer')], 48 | 49 | [['survey_user_answer_text'], 'required', 'when' => function($model){ 50 | /** @var $model SurveyUserAnswer */ 51 | return ($model->question->survey_question_can_skip == false && $model->question->survey_question_type === SurveyType::TYPE_COMMENT_BOX); 52 | }, 'message' => \Yii::t('survey', 'You must enter an answer')], 53 | 54 | [['survey_user_answer_value', 'survey_user_answer_text'], function ($attribute, $params, $validator) { 55 | /** @var $this SurveyUserAnswer */ 56 | if (!$this->question->survey->isAccessibleByCurrentUser) { 57 | $this->addError($attribute, \Yii::t('survey', 'You are not allowed to answer this survey')); 58 | } 59 | }], 60 | 61 | [['survey_user_answer_value', 'survey_user_answer_text'], 'default', 'value' => null], 62 | [['survey_user_answer_answer_id'], 'exist', 'skipOnError' => true, 'targetClass' => SurveyAnswer::class, 'targetAttribute' => ['survey_user_answer_answer_id' => 'survey_answer_id']], 63 | [['survey_user_answer_question_id'], 'exist', 'skipOnError' => true, 'targetClass' => SurveyQuestion::class, 'targetAttribute' => ['survey_user_answer_question_id' => 'survey_question_id']], 64 | [['survey_user_answer_survey_id'], 'exist', 'skipOnError' => true, 'targetClass' => Survey::class, 'targetAttribute' => ['survey_user_answer_survey_id' => 'survey_id']], 65 | [['survey_user_answer_user_id'], 'exist', 'skipOnError' => true, 'targetClass' => \Yii::$app->user->identityClass::className(), 'targetAttribute' => ['survey_user_answer_user_id' => 'id']], 66 | ]; 67 | } 68 | 69 | public function beforeValidate() 70 | { 71 | $stat = SurveyStat::getAssignedUserStat(\Yii::$app->user->getId(), $this->question->survey_question_survey_id); 72 | if ($stat && $stat->survey_stat_is_done){ 73 | return false; 74 | } 75 | 76 | return parent::beforeValidate(); 77 | } 78 | 79 | /** 80 | * @inheritdoc 81 | */ 82 | public function attributeLabels() 83 | { 84 | return [ 85 | 'survey_user_answer_id' => Yii::t('survey', 'Survey User Answer ID'), 86 | 'survey_user_answer_user_id' => Yii::t('survey', 'Survey User Answer User ID'), 87 | 'survey_user_answer_survey_id' => Yii::t('survey', 'Survey User Answer Survey ID'), 88 | 'survey_user_answer_question_id' => Yii::t('survey', 'Survey User Answer Question ID'), 89 | 'survey_user_answer_answer_id' => Yii::t('survey', 'Survey User Answer Answer ID'), 90 | 'survey_user_answer_value' => Yii::t('survey', 'Answer'), 91 | ]; 92 | } 93 | 94 | /** 95 | * @return \yii\db\ActiveQuery 96 | */ 97 | public function getSurveyUserAnswerAnswer() 98 | { 99 | return $this->hasOne(SurveyAnswer::class, ['survey_answer_id' => 'survey_user_answer_answer_id']); 100 | } 101 | 102 | /** 103 | * @return \yii\db\ActiveQuery 104 | */ 105 | public function getQuestion() 106 | { 107 | return $this->hasOne(SurveyQuestion::class, ['survey_question_id' => 'survey_user_answer_question_id']); 108 | } 109 | 110 | /** 111 | * @return \yii\db\ActiveQuery 112 | */ 113 | public function getSurveyUserAnswerSurvey() 114 | { 115 | return $this->hasOne(Survey::class, ['survey_id' => 'survey_user_answer_survey_id']); 116 | } 117 | 118 | /** 119 | * @return \yii\db\ActiveQuery 120 | */ 121 | public function getUser() 122 | { 123 | return $this->hasOne(\Yii::$app->user->identityClass::className(), ['id' => 'survey_user_answer_user_id']); 124 | } 125 | 126 | 127 | } 128 | -------------------------------------------------------------------------------- /models/search/SurveySearch.php: -------------------------------------------------------------------------------- 1 | $query, 49 | 'pagination' => ['defaultPageSize' => 10], 50 | 'sort' => ['defaultOrder' => ['survey_created_at' => SORT_DESC]] 51 | ]); 52 | 53 | $this->load($params); 54 | 55 | if (!$this->validate()) { 56 | // uncomment the following line if you do not want to return any records when validation fails 57 | $query->where('0=1'); 58 | return $dataProvider; 59 | } 60 | 61 | $query->andFilterWhere([ 62 | 'survey_id' => $this->survey_id, 63 | 'survey_created_at' => $this->survey_created_at, 64 | 'survey_updated_at' => $this->survey_updated_at, 65 | 'survey_expired_at' => $this->survey_expired_at, 66 | 'survey_is_pinned' => $this->survey_is_pinned, 67 | 'survey_is_closed' => $this->survey_is_closed, 68 | ]); 69 | 70 | $query->andFilterWhere(['like', 'survey_name', $this->survey_name]); 71 | 72 | return $dataProvider; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /models/search/SurveyStatSearch.php: -------------------------------------------------------------------------------- 1 | $query->joinWith('survey'), 49 | 'sort' => ['defaultOrder' => ['survey_stat_assigned_at' => SORT_DESC]] 50 | 51 | ]); 52 | 53 | $this->load($params); 54 | 55 | if (!$this->validate()) { 56 | // uncomment the following line if you do not want to return any records when validation fails 57 | $query->where('0=1'); 58 | return $dataProvider; 59 | } 60 | 61 | $query->andFilterWhere([ 62 | 'survey_stat_id' => $this->survey_stat_id, 63 | 'survey_stat_survey_id' => $this->survey_stat_survey_id, 64 | 'survey_stat_user_id' => $this->survey_stat_user_id, 65 | 'survey_stat_assigned_at' => $this->survey_stat_assigned_at, 66 | 'survey_stat_started_at' => $this->survey_stat_started_at, 67 | 'survey_stat_updated_at' => $this->survey_stat_updated_at, 68 | 'survey_stat_ended_at' => $this->survey_stat_ended_at, 69 | 'survey_stat_is_done' => $this->survey_stat_is_done, 70 | ]); 71 | 72 | $query->andFilterWhere(['like', 'survey_stat_ip', $this->survey_stat_ip]); 73 | 74 | return $dataProvider; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /views/answers/1.php: -------------------------------------------------------------------------------- 1 | answers as $i => $answer) { 17 | echo Html::checkbox('checkbox', false, ['class' => 'pseudo-checkbox']); 18 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_name")->input('text', 19 | ['placeholder' => \Yii::t('survey', 'Enter an answer choice')])->label(false); 20 | 21 | if ($question->survey_question_is_scorable) { 22 | echo Html::beginTag('div', ['class' => 'points-wrap']); 23 | if ($i === 0) { 24 | echo Html::tag('span', 'Баллы', ['class' => 'points-title']); 25 | } 26 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_points")->input('number')->label(false); 27 | echo Html::endTag('div'); 28 | } 29 | 30 | echo Html::submitButton('', ['class' => 'btn btn-success btn-add-answer survey-question-submit', 31 | 'data-action' => Url::toRoute(['question/add-answer', 'id' => $question->survey_question_id, 'after' => $i])]); 32 | echo Html::submitButton('', ['class' => 'btn btn-danger btn-delete-answer survey-question-submit', 33 | 'data-action' => Url::toRoute(['question/delete-answer', 'id' => $question->survey_question_id, 'answer' => $i]), 34 | 'name' => 'action', 'value' => 'delete-answer' 35 | ]); 36 | 37 | echo $form->field($answer, "[{$question->survey_question_id}][$i]survey_answer_show_descr", 38 | ['options' => [ 39 | 'class' => 'form-group checkbox-inline' 40 | ]])->checkbox(['class' => 'checkbox-updatable']); 41 | echo Html::tag('br', ''); 42 | 43 | if ($answer->survey_answer_show_descr) { 44 | echo $form->field($answer, "[{$question->survey_question_id}][$i]survey_answer_descr")->widget(Widget::class, [ 45 | 'settings' => [ 46 | 'lang' => 'ru', 47 | 'minHeight' => 100, 48 | 'toolbarFixed' => false, 49 | 'imageManagerJson' => Url::toRoute(['question/images-get']), 50 | 'imageUpload' => Url::toRoute(['question/image-upload']), 51 | 'fileManagerJson' => Url::toRoute(['question/files-get']), 52 | 'fileUpload' => Url::toRoute(['question/file-upload']), 53 | 'plugins' => [ 54 | 'imagemanager', 55 | 'video', 56 | 'fullscreen', 57 | 'filemanager', 58 | 'fontsize', 59 | 'fontcolor', 60 | 'table', 61 | ] 62 | ] 63 | ])->label(false); 64 | } 65 | 66 | echo Html::tag('br', ''); 67 | } -------------------------------------------------------------------------------- /views/answers/10.php: -------------------------------------------------------------------------------- 1 | field() 10 | foreach ($question->answers as $i => $answer) { 11 | 12 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_name")->input('text', 13 | ['placeholder' => \Yii::t('survey', 'Enter an answer choice')])->label(false); 14 | 15 | if ($question->survey_question_is_scorable) { 16 | echo Html::beginTag('div', ['class' => 'points-wrap']); 17 | if ($i === 0) { 18 | echo Html::tag('span', 'Баллы', ['class' => 'points-title']); 19 | } 20 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_points")->input('number')->label(false); 21 | echo Html::endTag('div'); 22 | } 23 | 24 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-success btn-add-answer survey-question-submit', 25 | 'data-action' => Url::toRoute(['question/add-answer', 'id' => $question->survey_question_id, 'after' => $i])]); 26 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-danger btn-delete-answer survey-question-submit', 27 | 'data-action' => Url::toRoute(['question/delete-answer', 'id' => $question->survey_question_id, 'answer' => $i]), 28 | 'name' => 'action', 'value' => 'delete-answer' 29 | ]); 30 | 31 | echo Html::tag('br', ''); 32 | } -------------------------------------------------------------------------------- /views/answers/2.php: -------------------------------------------------------------------------------- 1 | field() 17 | foreach ($question->answers as $i => $answer) { 18 | echo Html::radio('radio', false, ['class' => 'pseudo-checkbox']); 19 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_name")->input('text', 20 | ['placeholder' => \Yii::t('survey', 'Enter an answer choice')])->label(false); 21 | 22 | if ($question->survey_question_is_scorable) { 23 | echo Html::beginTag('div', ['class' => 'points-wrap']); 24 | if ($i === 0) { 25 | echo Html::tag('span', 'Баллы', ['class' => 'points-title']); 26 | } 27 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_points")->input('number')->label(false); 28 | echo Html::endTag('div'); 29 | } 30 | 31 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-success btn-add-answer survey-question-submit', 32 | 'data-action' => Url::toRoute(['question/add-answer', 'id' => $question->survey_question_id, 'after' => $i])]); 33 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-danger btn-delete-answer survey-question-submit', 34 | 'data-action' => Url::toRoute(['question/delete-answer', 'id' => $question->survey_question_id, 'answer' => $i]), 35 | 'name' => 'action', 'value' => 'delete-answer' 36 | ]); 37 | 38 | echo $form->field($answer, "[{$question->survey_question_id}][$i]survey_answer_show_descr", 39 | ['options' => [ 40 | 'class' => 'form-group checkbox-inline' 41 | ]])->checkbox(['class' => 'checkbox-updatable']); 42 | echo Html::tag('br', ''); 43 | 44 | if ($answer->survey_answer_show_descr) { 45 | echo $form->field($answer, "[{$question->survey_question_id}][$i]survey_answer_descr")->widget(Widget::class, [ 46 | 'settings' => [ 47 | 'lang' => 'ru', 48 | 'minHeight' => 100, 49 | 'toolbarFixed' => false, 50 | 'imageManagerJson' => Url::toRoute(['question/images-get']), 51 | 'imageUpload' => Url::toRoute(['question/image-upload']), 52 | 'fileManagerJson' => Url::toRoute(['question/files-get']), 53 | 'fileUpload' => Url::toRoute(['question/file-upload']), 54 | 'plugins' => [ 55 | 'imagemanager', 56 | 'video', 57 | 'fullscreen', 58 | 'filemanager', 59 | 'fontsize', 60 | 'fontcolor', 61 | 'table', 62 | ] 63 | ] 64 | ])->label(false); 65 | } 66 | 67 | echo Html::tag('br', ''); 68 | } -------------------------------------------------------------------------------- /views/answers/3.php: -------------------------------------------------------------------------------- 1 | field() 16 | foreach ($question->answers as $i => $answer) { 17 | 18 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_name")->input('text', 19 | ['placeholder' => \Yii::t('survey', 'Enter an answer choice')])->label(false); 20 | 21 | if ($question->survey_question_is_scorable) { 22 | echo Html::beginTag('div', ['class' => 'points-wrap']); 23 | if ($i === 0) { 24 | echo Html::tag('span', 'Баллы', ['class' => 'points-title']); 25 | } 26 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_points")->input('number')->label(false); 27 | echo Html::endTag('div'); 28 | } 29 | 30 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-success btn-add-answer survey-question-submit', 31 | 'data-action' => Url::toRoute(['question/add-answer', 'id' => $question->survey_question_id, 'after' => $i])]); 32 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-danger btn-delete-answer survey-question-submit', 33 | 'data-action' => Url::toRoute(['question/delete-answer', 'id' => $question->survey_question_id, 'answer' => $i]), 34 | 'name' => 'action', 'value' => 'delete-answer' 35 | ]); 36 | 37 | echo Html::tag('br', ''); 38 | } -------------------------------------------------------------------------------- /views/answers/4.php: -------------------------------------------------------------------------------- 1 | field() 17 | foreach ($question->answers as $i => $answer) { 18 | 19 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_name")->input('text', 20 | ['placeholder' => \Yii::t('survey', 'Enter an answer choice')])->label(false); 21 | 22 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-success btn-add-answer survey-question-submit', 23 | 'data-action' => Url::toRoute(['question/add-answer', 'id' => $question->survey_question_id, 'after' => $i])]); 24 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-danger btn-delete-answer survey-question-submit', 25 | 'data-action' => Url::toRoute(['question/delete-answer', 'id' => $question->survey_question_id, 'answer' => $i]), 26 | 'name' => 'action', 'value' => 'delete-answer' 27 | ]); 28 | 29 | echo $form->field($answer, "[{$question->survey_question_id}][$i]survey_answer_show_descr", 30 | ['options' => [ 31 | 'class' => 'form-group checkbox-inline' 32 | ]])->checkbox(['class' => 'checkbox-updatable']); 33 | echo Html::tag('br', ''); 34 | 35 | if ($answer->survey_answer_show_descr) { 36 | echo $form->field($answer, "[{$question->survey_question_id}][$i]survey_answer_descr")->widget(Widget::class, [ 37 | 'settings' => [ 38 | 'lang' => 'ru', 39 | 'minHeight' => 100, 40 | 'toolbarFixed' => false, 41 | 'imageManagerJson' => Url::toRoute(['question/images-get']), 42 | 'imageUpload' => Url::toRoute(['question/image-upload']), 43 | 'fileManagerJson' => Url::toRoute(['question/files-get']), 44 | 'fileUpload' => Url::toRoute(['question/file-upload']), 45 | 'plugins' => [ 46 | 'imagemanager', 47 | 'video', 48 | 'fullscreen', 49 | 'filemanager', 50 | 'fontsize', 51 | 'fontcolor', 52 | 'table', 53 | ] 54 | ] 55 | ])->label(false); 56 | } 57 | 58 | echo Html::tag('br', ''); 59 | } -------------------------------------------------------------------------------- /views/answers/5.php: -------------------------------------------------------------------------------- 1 | answers as $i => $answer) { 16 | switch ($i){ 17 | case 0: 18 | $label = 'Min'; 19 | break; 20 | case 1: 21 | $label = 'Max'; 22 | break; 23 | default: 24 | $label = false; 25 | break; 26 | } 27 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_name", [ 28 | 'template' => "
{label}{input}\n{error}
" 29 | ])->input('number', 30 | ['placeholder' => \Yii::t('survey', 'Enter an answer choice')])->label($label); 31 | 32 | echo Html::tag('br', ''); 33 | } -------------------------------------------------------------------------------- /views/answers/6.php: -------------------------------------------------------------------------------- 1 | field() 17 | foreach ($question->answers as $i => $answer) { 18 | 19 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_name", [ 20 | 'template' => "
{label}{input}
\n{error}
", 21 | ])->input('text')->label(\Yii::t('survey', 'Label') . ' ' . ($i + 1)); 22 | 23 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-success btn-add-answer survey-question-submit', 24 | 'data-action' => Url::toRoute(['question/add-answer', 'id' => $question->survey_question_id, 'after' => $i])]); 25 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-danger btn-delete-answer survey-question-submit', 26 | 'data-action' => Url::toRoute(['question/delete-answer', 'id' => $question->survey_question_id, 'answer' => $i]), 27 | 'name' => 'action', 'value' => 'delete-answer' 28 | ]); 29 | 30 | echo Html::tag('br', ''); 31 | } -------------------------------------------------------------------------------- /views/answers/8.php: -------------------------------------------------------------------------------- 1 | field() 17 | foreach ($question->answers as $i => $answer) { 18 | 19 | echo $form->field($answer, "[$question->survey_question_id][$i]survey_answer_name", [ 20 | 'template' => "
{label}{input}
\n{error}
", 21 | ])->input('text')->label(\Yii::t('survey', 'Label') . ' ' . ($i + 1)); 22 | 23 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-success btn-add-answer survey-question-submit', 24 | 'data-action' => Url::toRoute(['question/add-answer', 'id' => $question->survey_question_id, 'after' => $i])]); 25 | echo Html::submitButton(\Yii::t('survey', ''), ['class' => 'btn btn-danger btn-delete-answer survey-question-submit', 26 | 'data-action' => Url::toRoute(['question/delete-answer', 'id' => $question->survey_question_id, 'answer' => $i]), 27 | 'name' => 'action', 'value' => 'delete-answer' 28 | ]); 29 | 30 | echo Html::tag('br', ''); 31 | } -------------------------------------------------------------------------------- /views/answers/_form.php: -------------------------------------------------------------------------------- 1 | render('/answers/' . $question->survey_question_type, ['question' => $question, 'form' => $form]); -------------------------------------------------------------------------------- /views/answers/view/1.php: -------------------------------------------------------------------------------- 1 | getTotalUserAnswersCount(); 19 | 20 | echo Html::beginTag('div', ['class' => 'answers-stat']); 21 | foreach ($question->answers as $i => $answer) { 22 | $count = $answer->getTotalUserAnswersCount(); 23 | try { 24 | $percent = ($count / $totalVotesCount) * 100; 25 | }catch (\Exception $e){ 26 | $percent = 0; 27 | } 28 | echo $answer->survey_answer_name; 29 | echo Progress::widget([ 30 | 'id' => 'progress-' . $answer->survey_answer_id, 31 | 'percent' => $percent, 32 | 'label' => $count, 33 | 'barOptions' => ['class' => 'progress-bar-info init'] 34 | ]); 35 | } 36 | echo Html::endTag('div'); 37 | -------------------------------------------------------------------------------- /views/answers/view/10.php: -------------------------------------------------------------------------------- 1 | getTotalUserAnswersCount(); 12 | 13 | ?> 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | [ 29 | 'value' => '', 30 | 'count' => 0 31 | ], 32 | 3 => [ 33 | 'value' => '', 34 | 'count' => 0 35 | ] 36 | ]; 37 | 38 | foreach ($question->answers as $i => $answer) { 39 | $count = [ 40 | 1 => 0, 41 | 2 => 0, 42 | 3 => 0 43 | ]; 44 | 45 | foreach ($answer->userAnswers as $userAnswer) { 46 | $count[$userAnswer->survey_user_answer_value]++; 47 | } 48 | 49 | if ($betterChoice[1]['count'] < $count[1]) { 50 | $betterChoice[1]['value'] = $answer->survey_answer_name; 51 | $betterChoice[1]['count'] = $count[1]; 52 | } else if ($count[1] && $betterChoice[1]['count'] == $count[1]) { 53 | $betterChoice[1]['value'] .= \Yii::t('survey', ' or ') . $answer->survey_answer_name; 54 | } 55 | 56 | if ($betterChoice[3]['count'] < $count[1] + $count[3]) { 57 | $betterChoice[3]['value'] = $answer->survey_answer_name; 58 | $betterChoice[3]['count'] = $count[1] + $count[3]; 59 | } else if ($count[1] + $count[3] && $betterChoice[1]['count'] == $count[1] + $count[3]) { 60 | $betterChoice[3]['value'] .= \Yii::t('survey', ' or ') . $answer->survey_answer_name; 61 | } 62 | 63 | echo Html::beginTag('tr') 64 | . Html::tag('td', $answer->survey_answer_name) 65 | . Html::tag('td', $count[1]) 66 | . Html::tag('td', $count[2]) 67 | . Html::tag('td', $count[3]) 68 | . Html::tag('td', ($count[1] + $count[3]) . ($count[1] && $count[3] == 0 ? ' *' : '')) 69 | . Html::endTag('tr'); 70 | } 71 | ?> 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 |
-------------------------------------------------------------------------------- /views/answers/view/2.php: -------------------------------------------------------------------------------- 1 | getTotalUserAnswersCount(); 18 | 19 | echo Html::beginTag('div', ['class' => 'answers-stat']); 20 | foreach ($question->answers as $i => $answer) { 21 | $count = $answer->getTotalUserAnswersCount(); 22 | try { 23 | $percent = ($count / $totalVotesCount) * 100; 24 | }catch (\Exception $e){ 25 | $percent = 0; 26 | } 27 | echo $answer->survey_answer_name; 28 | echo Progress::widget([ 29 | 'id' => 'progress-' . $answer->survey_answer_id, 30 | 'percent' => $percent, 31 | 'label' => $count, 32 | 'barOptions' => ['class' => 'progress-bar-info init'] 33 | ]); 34 | } 35 | echo Html::endTag('div'); -------------------------------------------------------------------------------- /views/answers/view/3.php: -------------------------------------------------------------------------------- 1 | getTotalUserAnswersCount(); 17 | 18 | echo Html::beginTag('div', ['class' => 'answers-stat']); 19 | foreach ($question->answers as $i => $answer) { 20 | $count = $answer->getTotalUserAnswersCount(); 21 | try { 22 | $percent = ($count / $totalVotesCount) * 100; 23 | }catch (\Exception $e){ 24 | $percent = 0; 25 | } 26 | echo $answer->survey_answer_name; 27 | echo Progress::widget([ 28 | 'id' => 'progress-' . $answer->survey_answer_id, 29 | 'percent' => $percent, 30 | 'label' => $count, 31 | 'barOptions' => ['class' => 'progress-bar-info init'] 32 | ]); 33 | } 34 | echo Html::endTag('div'); -------------------------------------------------------------------------------- /views/answers/view/4.php: -------------------------------------------------------------------------------- 1 | 'answers-stat']); 18 | foreach ($question->answers as $i => $answer) { 19 | $average = $answer->getTotalUserAnswersCount(); 20 | $average = $average > 0 ? round($average, 1) : 0; 21 | echo Html::label($answer->survey_answer_name) . ' - ' . "average $average"; 22 | echo Html::tag('br', ''); 23 | } 24 | echo Html::endTag('div'); -------------------------------------------------------------------------------- /views/answers/view/5.php: -------------------------------------------------------------------------------- 1 | 'answers-stat']); 19 | 20 | $average = $question->answers[0]->getTotalUserAnswersCount(); 21 | $average = $average > 0 ? round($average, 1) : 0; 22 | echo "average $average"; 23 | 24 | echo Html::endTag('div'); -------------------------------------------------------------------------------- /views/answers/view/6.php: -------------------------------------------------------------------------------- 1 | render('/answers/view/' . $question->survey_question_type, ['question' => $question]); -------------------------------------------------------------------------------- /views/default/_form.php: -------------------------------------------------------------------------------- 1 | 27 |
28 | 29 |
30 | 'survey-name-wrap']); 33 | 34 | \yii\widgets\Pjax::begin([ 35 | 'id' => 'form-photo-pjax', 36 | 'timeout' => 0, 37 | 'enablePushState' => false 38 | ]); 39 | $form = ActiveForm::begin([ 40 | 'id' => 'survey-photo-form', 41 | 'action' => \yii\helpers\Url::toRoute(['default/update-image', 'id' => $survey->survey_id]), 42 | 'options' => ['class' => 'form-horizontal', 'data-pjax' => true], 43 | // 'enableAjaxValidation' => true, 44 | ]); 45 | 46 | echo UploadCrop::widget([ 47 | 'form' => $form, 48 | 'model' => $survey, 49 | 'attribute' => 'imageFile', 50 | 'enableClientValidation' => true, 51 | 'defaultPreviewImage' => $survey->getImage(), 52 | 'jcropOptions' => [ 53 | // 'dragMode' => 'none', 54 | 'viewMode' => 2, 55 | 'aspectRatio' => 1, 56 | 'autoCropArea' => 1, 57 | 'rotatable' => true, 58 | 'scalable' => true, 59 | 'zoomable' => true, 60 | 'toggleDragModeOnDblclick' => false 61 | ] 62 | ]); 63 | 64 | ActiveForm::end(); 65 | \yii\widgets\Pjax::end(); 66 | 67 | echo Editable::widget([ 68 | 'model' => $survey, 69 | 'attribute' => 'survey_name', 70 | 'asPopover' => true, 71 | 'header' => 'Name', 72 | 'size' => 'md', 73 | 'formOptions' => [ 74 | 'action' => Url::toRoute(['default/update-editable', 'property' => 'survey_name']) 75 | ], 76 | 'additionalData' => ['id' => $survey->survey_id], 77 | 'options' => [ 78 | 'class' => 'form-control', 79 | 'placeholder' => 'Enter survey name...', 80 | ] 81 | ]); 82 | echo Html::endTag('div'); 83 | 84 | 85 | echo Html::tag('br', ''); 86 | 87 | echo Html::beginTag('div', ['class' => 'survey-content-wrap']); 88 | echo Html::beginTag('div', ['class' => 'row']); 89 | echo Html::beginTag('div', ['class' => 'col-md-6']); 90 | echo Html::label(Yii::t('survey', 'Expired at') . ': ', 'survey-survey_expired_at'); 91 | echo Editable::widget([ 92 | 'model' => $survey, 93 | 'attribute' => 'survey_expired_at', 94 | 'header' => 'Expired at', 95 | 'asPopover' => true, 96 | 'size' => 'md', 97 | 'inputType' => Editable::INPUT_DATETIME, 98 | 'formOptions' => [ 99 | 'action' => Url::toRoute(['default/update-editable', 'property' => 'survey_expired_at']) 100 | ], 101 | 'additionalData' => ['id' => $survey->survey_id], 102 | 'options' => [ 103 | 'class' => Editable::INPUT_DATETIME, 104 | 'pluginOptions' => [ 105 | 'autoclose' => true, 106 | // 'format' => 'd.m.Y H:i' 107 | ], 108 | 'options' => ['placeholder' => 'Expired at'] 109 | ], 110 | 'showButtonLabels' => true, 111 | 'submitButton' => [ 112 | 'icon' => false, 113 | 'label' => 'OK', 114 | 'class' => 'btn btn-sm btn-primary' 115 | ] 116 | ]); 117 | echo Html::endTag('div'); // col-md-6 118 | 119 | echo Html::beginTag('div', ['class' => 'col-md-6']); 120 | echo Html::label(Yii::t('survey', 'Time to pass') . ': ', 'survey-survey_time_to_pass'); 121 | echo Editable::widget([ 122 | 'model' => $survey, 123 | 'attribute' => 'survey_time_to_pass', 124 | 'asPopover' => true, 125 | 'header' => 'Time to pass', 126 | 'size' => 'md', 127 | 'formOptions' => [ 128 | 'action' => Url::toRoute(['default/update-editable', 'property' => 'survey_time_to_pass']) 129 | ], 130 | 'additionalData' => ['id' => $survey->survey_id], 131 | 'options' => [ 132 | 'class' => 'form-control', 133 | 'placeholder' => 'Enter time in minutes...', 134 | 'type' => 'number', 135 | ] 136 | ]); 137 | echo Html::label(Yii::t('survey', 'minutes')); 138 | echo Html::endTag('div'); // col-md-6 139 | 140 | echo Html::endTag('div'); // row 141 | 142 | 143 | Pjax::begin([ 144 | 'id' => 'survey-pjax', 145 | 'enablePushState' => false, 146 | 'timeout' => 0, 147 | 'scrollTo' => false, 148 | 'clientOptions' => [ 149 | 'type' => 'post', 150 | 'skipOuterContainers' => true, 151 | ] 152 | ]); 153 | 154 | $form = ActiveForm::begin([ 155 | 'id' => 'survey-form', 156 | 'action' => Url::toRoute(['default/update', 'id' => $survey->survey_id]), 157 | 'options' => ['class' => 'form-inline', 'data-pjax' => true], 158 | 'enableClientValidation' => false, 159 | 'enableAjaxValidation' => false, 160 | 'fieldConfig' => [ 161 | 'template' => "
{label}{input}\n{error}
", 162 | 'labelOptions' => ['class' => ''], 163 | ], 164 | ]); 165 | 166 | echo Html::beginTag('div', ['class' => 'row']); 167 | echo Html::beginTag('div', ['class' => 'col-md-12']); 168 | echo $form->field($survey, "survey_descr", ['template' => "
{label}{input}
",] 169 | )->textarea(['rows' => 3]); 170 | echo Html::tag('div', '', ['class' => 'clearfix']); 171 | echo Html::endTag('div'); // col-md-12 172 | echo Html::endTag('div'); // row 173 | 174 | echo Html::beginTag('div', ['class' => 'row']); 175 | echo Html::beginTag('div', ['class' => 'col-md-3']); 176 | echo $form->field($survey, "survey_is_closed", ['template' => "
{input}{label}
",] 177 | )->checkbox(['class' => 'checkbox danger'], false); 178 | echo Html::tag('div', '', ['class' => 'clearfix']); 179 | echo $form->field($survey, "survey_is_pinned", ['template' => "
{input}{label}
",] 180 | )->checkbox(['class' => 'checkbox'], false); 181 | echo Html::tag('div', '', ['class' => 'clearfix']); 182 | echo $form->field($survey, "survey_is_visible", ['template' => "
{input}{label}
",] 183 | )->checkbox(['class' => 'checkbox'], false); 184 | if ($withUserSearch) { 185 | echo Html::tag('div', '', ['class' => 'clearfix']); 186 | echo $form->field($survey, 187 | "survey_is_private", 188 | ['template' => "
{input}{label}
",] 189 | )->checkbox(['class' => 'checkbox danger'], false); 190 | } 191 | echo Html::endTag('div'); // col-md-3 192 | 193 | echo Html::beginTag('div', ['class' => 'col-md-9']); 194 | echo $form->field($survey, "survey_tags")->input('text', ['placeholder' => 'Comma separated']); 195 | if ($withUserSearch) { 196 | echo Html::tag('div', '', ['class' => 'clearfix']); 197 | echo $form->field($survey, 'restrictedUserIds')->widget(Select2::classname(), 198 | [ 199 | 'initValueText' => $survey->restrictedUsernames, // set the initial display text 200 | 'options' => ['placeholder' => \Yii::t('survey', 'Restrict survey to selected user...')], 201 | 'pluginOptions' => [ 202 | 'allowClear' => true, 203 | 'minimumInputLength' => 3, 204 | 'language' => [ 205 | 'errorLoading' => new JsExpression("function () { return 'Waiting for results...'; }"), 206 | ], 207 | 'ajax' => [ 208 | 'url' => Url::toRoute(['default/search-respondents-by-token']), 209 | 'dataType' => 'json', 210 | 'data' => new JsExpression('function(params) { return {token:params.term}; }') 211 | ], 212 | 'multiple' => true, 213 | 'escapeMarkup' => new JsExpression('function (markup) { return markup; }'), 214 | 'templateResult' => new JsExpression('function(city) { return city.text; }'), 215 | 'templateSelection' => new JsExpression('function (city) { return city.text; }'), 216 | ], 217 | 'pluginEvents' => [ 218 | 'change' => new JsExpression('function() { 219 | var container = $(this).closest(\'[data-pjax-container]\'); 220 | container.find(\'button[type=submit]\').click(); 221 | }') 222 | ] 223 | ]); 224 | } 225 | echo Html::endTag('div'); // col-md-9 226 | echo Html::endTag('div'); // row 227 | 228 | echo Html::submitButton('', ['class' => 'hidden']); 229 | echo Html::tag('div', '', ['class' => 'clearfix']); 230 | 231 | ActiveForm::end(); 232 | 233 | Pjax::end(); 234 | echo Html::endTag('div'); 235 | 236 | ?> 237 |
238 |
239 |
240 |
241 | questions as $i => $question) { 243 | echo $this->render('/question/_form', ['question' => $question]); 244 | } 245 | ?> 246 |
247 | 'survey-questions-append']); 249 | 250 | Pjax::begin([ 251 | 'id' => 'survey-questions-pjax', 252 | 'enablePushState' => false, 253 | 'timeout' => 0, 254 | 'scrollTo' => false, 255 | 'clientOptions' => [ 256 | 'type' => 'post', 257 | 'container' => '#survey-questions-append', 258 | 'skipOuterContainers' => true, 259 | ] 260 | ]); 261 | echo Html::tag('div', Html::a(' ' . Yii::t('survey', 'Add question'), Url::toRoute(['question/create', 'id' => $survey->survey_id]), ['class' => 'btn btn-success']), 262 | ['class' => 'text-center survey-btn', 'id' => '']); 263 | echo Html::tag('div', Html::submitButton(' ' . Yii::t('survey', 'Save'), 264 | ['class' => 'btn btn-primary', 'data-default-text' => ' ' . Yii::t('survey', 'Save')]), ['class' => 'text-center survey-btn', 'id' => 'save', 'data-action' => Url::toRoute(['default/view', 'id' => $survey->survey_id])]); 265 | 266 | Pjax::end(); ?> 267 | 268 | 269 |
270 | 271 | registerJs(<<registerCss(<<registerJs(<<title = Yii::t('survey', 'Create new survey'); 20 | 21 | 22 | echo $this->render('_form', [ 23 | 'survey' => $survey, 24 | 'withUserSearch' => $withUserSearch 25 | ]); 26 | 27 | -------------------------------------------------------------------------------- /views/default/index.php: -------------------------------------------------------------------------------- 1 | 20 |
21 | 'btn btn-success pull-right']); 23 | 24 | Pjax::begin([ 25 | 'id' => 'survey-index-pjax', 26 | 'enablePushState' => true, 27 | 'timeout' => 0]); 28 | 29 | echo ListView::widget(['id' => 'survey-list', 30 | 'layout' => "{summary}\n{items}\n
{pager}
", 31 | 'dataProvider' => $dataProvider, 32 | 'itemOptions' => ['class' => 'item'], 33 | 'itemView' => function ($model, $key, $index, $widget) { 34 | /** @var $model \onmotion\survey\models\Survey */ 35 | $survey = $model; 36 | $image = $survey->getImage(); 37 | ob_start(); 38 | ?> 39 |
40 |
41 |
42 |
43 |
>
48 |
49 |
50 | survey_name) ?> 53 |
54 |
55 |
56 | getRespondentsCount() ?> 58 | getCompletedRespondentsCount() ?> 60 | getQuestions()->count() ?> 62 |
63 |
64 | 67 | '), Url::toRoute(['default/delete', 'id' => $survey->survey_id]), [ 69 | 'class' => 'btn btn-danger btn-xs pull-right btn-delete', 70 | 'data-pjax' => 0, 71 | 'role' => 'remote-modal', 72 | 'data-confirm-message' => 'Are you sure?', 73 | 'data-method' => false,// for overide yii data api 74 | 'data-request-method' => 'post', 75 | ]); 76 | ?> 77 |
78 |
79 |
80 |
81 |
82 | Author: getAuthorName() ?> 83 | Created At: formatter->asDate($survey->survey_created_at) ?> 84 |
85 |
86 |
87 | 94 | 95 |
96 | 97 | "remote-modal", 99 | "options" => ["class" => "fade "], 100 | "footer" => "", // always need it for jquery plugin 101 | ]) ?> 102 | 103 | 104 | registerJs(<< 17 |
18 | 19 | 'addition-form']); 23 | 24 | echo Html::label(\Yii::t('survey', 'Add respondents'), [], ['class' => 'control-label']); 25 | 26 | $assignUrl = Url::toRoute(['default/assign-user', 'surveyId' => $surveyId]); 27 | $pjaxUrl = Url::toRoute(['default/respondents', 'surveyId' => $surveyId]); 28 | echo Typeahead::widget([ 29 | 'name' => 'respondents', 30 | 'id' => 'respondents-typeahead', 31 | 'scrollable' => true, 32 | 'dataset' => [ 33 | [ 34 | 'display' => 'text', 35 | 'remote' => [ 36 | 'url' => Url::toRoute(['default/get-respondents-by-token', 'surveyId' => $surveyId]) . '&token=%QUERY', 37 | 'wildcard' => '%QUERY', 38 | 'rateLimitWait' => 300 39 | ], 40 | 'limit' => 20, 41 | 'templates' => [ 42 | 'notFound' => '
' . \Yii::t('survey', 'No result found.') . '
', 43 | 'suggestion' => new \yii\web\JsExpression(<<'+ data.text +'
'; 47 | }else{ 48 | return '
'+ data.text +'
'; 49 | } 50 | } 51 | JS 52 | ), 53 | ], 54 | ] 55 | ], 56 | 'pluginOptions' => [ 57 | 'highlight' => true, 58 | 'minLength' => 2, 59 | 'val' => '', 60 | ], 61 | 'pluginEvents' => [ 62 | "typeahead:selected" => << ['placeholder' => 'Type some words...'], 79 | ]); 80 | echo Html::endTag('div'); 81 | } 82 | 83 | Pjax::begin([ 84 | 'id' => 'survey-respondents-pjax', 85 | 'enableReplaceState' => false, 86 | 'enablePushState' => false, 87 | 'timeout' => 0, 88 | 'clientOptions' => [ 89 | // 'async' => false 90 | ], 91 | ]); 92 | 93 | ActiveForm::begin([ 94 | 'id' => 'survey-respondents-form', 95 | 'action' => Url::toRoute(['default/unassign-user', 'surveyId' => $surveyId]), 96 | 'enableClientValidation' => false, 97 | 'enableAjaxValidation' => false, 98 | 'options' => ['data-pjax' => true], 99 | ]); 100 | 101 | echo ListView::widget([ 102 | 'id' => 'survey-respondents-list', 103 | 'layout' => "
{summary}
\n
{items}\n
{pager}
", 104 | 'dataProvider' => $dataProvider, 105 | 'itemOptions' => ['class' => 'item'], 106 | 'itemView' => function ($model, $key, $index, $widget) use ($surveyId) { 107 | /** @var $model \onmotion\survey\models\SurveyStat */ 108 | $surveyStat = $model; 109 | ob_start(); 110 | ?> 111 |
112 | user->fullname 114 | ?> 115 | 116 |
117 |
118 | '), 120 | [ 121 | 'class' => 'btn btn-danger btn-delete-assigned-user user-assign-submit', 122 | 'data-action' => Url::toRoute(['default/unassign-user', 'surveyId' => $surveyId]), 123 | 'name' => 'userId', 124 | 'value' => $surveyStat->survey_stat_user_id 125 | ]); 126 | ?> 127 |
128 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /views/default/restrictedUsers.php: -------------------------------------------------------------------------------- 1 | 16 |
17 | 18 | 'addition-form']); 21 | 22 | echo Html::label(\Yii::t('survey', 'Add restricted users'), [], ['class' => 'control-label']); 23 | 24 | $assignUrl = Url::toRoute(['default/assign-restricted-user', 'surveyId' => $surveyId]); 25 | $pjaxUrl = Url::toRoute(['default/restricted-users', 'surveyId' => $surveyId]); 26 | echo Typeahead::widget([ 27 | 'name' => 'restricted-users', 28 | 'id' => 'restricted-users-typeahead', 29 | 'scrollable' => true, 30 | 'dataset' => [ 31 | [ 32 | 'display' => 'text', 33 | 'remote' => [ 34 | 'url' => Url::toRoute(['default/get-respondents-by-token', 'surveyId' => $surveyId]) . '&token=%QUERY', 35 | 'wildcard' => '%QUERY', 36 | 'rateLimitWait' => 300 37 | ], 38 | 'limit' => 20, 39 | 'templates' => [ 40 | 'notFound' => '
' . \Yii::t('survey', 'No result found.') . '
', 41 | 'suggestion' => new \yii\web\JsExpression(<<'+ data.text +'
'; 45 | }else{ 46 | return '
'+ data.text +'
'; 47 | } 48 | } 49 | JS 50 | ), 51 | ], 52 | ] 53 | ], 54 | 'pluginOptions' => [ 55 | 'highlight' => true, 56 | 'minLength' => 2, 57 | 'val' => '', 58 | ], 59 | 'pluginEvents' => [ 60 | "typeahead:selected" => << ['placeholder' => 'Type some words...'], 77 | ]); 78 | echo Html::endTag('div'); 79 | 80 | Pjax::begin([ 81 | 'id' => 'survey-restricted-users-pjax', 82 | 'enableReplaceState' => false, 83 | 'enablePushState' => false, 84 | 'timeout' => 0, 85 | 'clientOptions' => [ 86 | // 'async' => false 87 | ], 88 | ]); 89 | 90 | ActiveForm::begin([ 91 | 'id' => 'survey-restricted-users-form', 92 | 'action' => Url::toRoute(['default/unassign-user', 'surveyId' => $surveyId]), 93 | 'enableClientValidation' => false, 94 | 'enableAjaxValidation' => false, 95 | 'options' => ['data-pjax' => true], 96 | ]); 97 | 98 | echo ListView::widget([ 99 | 'id' => 'survey-restricted-users-list', 100 | 'layout' => "
{summary}
\n
{items}\n
{pager}
", 101 | 'dataProvider' => $restrictedUserDataProvider, 102 | 'itemOptions' => ['class' => 'item'], 103 | 'itemView' => function ($model, $key, $index, $widget) use ($surveyId) { 104 | ob_start(); 105 | ?> 106 |
107 | fullname 109 | ?> 110 | 111 |
112 |
113 | '), 115 | [ 116 | 'class' => 'btn btn-danger btn-delete-assigned-user user-assign-submit', 117 | 'data-action' => Url::toRoute(['default/unassign-restricted-user', 'surveyId' => $surveyId]), 118 | 'name' => 'userId', 119 | 'value' => $model->id 120 | ]); 121 | ?> 122 |
123 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /views/default/update.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('survey', 'Update survey'); 19 | 20 | 21 | echo $this->render('_form', [ 22 | 'survey' => $survey, 23 | 'withUserSearch' => $withUserSearch 24 | ]); -------------------------------------------------------------------------------- /views/default/view.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('survey', 'Survey') . ' - ' . $survey->survey_name; 27 | 28 | BootstrapPluginAsset::register($this); 29 | 30 | 31 | ?> 32 |
33 |
34 |
35 |

survey_name; ?>

36 |
37 |
38 | 41 | : getRespondentsCount() ?> 43 | : getQuestions()->count() ?> 45 | : getRestrictedUsersCount() ?> 47 |
48 | 49 |
50 | 51 |
52 |
53 | 'row']); 55 | echo Html::beginTag('div', ['class' => 'col-md-6']); 56 | echo Html::label(Yii::t('survey', 'Expired at') . ': ', 'survey-survey_expired_at'); 57 | echo Editable::widget([ 58 | 'model' => $survey, 59 | 'attribute' => 'survey_expired_at', 60 | 'header' => 'Expired at', 61 | 'asPopover' => true, 62 | 'size' => 'md', 63 | 'inputType' => Editable::INPUT_DATETIME, 64 | 'formOptions' => [ 65 | 'action' => Url::toRoute(['default/update-editable', 'property' => 'survey_expired_at']) 66 | ], 67 | 'additionalData' => ['id' => $survey->survey_id], 68 | 'options' => [ 69 | 'class' => Editable::INPUT_DATETIME, 70 | 'pluginOptions' => [ 71 | 'autoclose' => true, 72 | // 'format' => 'd.m.Y H:i' 73 | ], 74 | 'options' => ['placeholder' => 'Expired at'] 75 | ] 76 | ]); 77 | echo Html::endTag('div'); 78 | 79 | echo Html::beginTag('div', ['class' => 'col-md-6']); 80 | echo Html::endTag('div'); 81 | echo Html::endTag('div'); 82 | 83 | Pjax::begin([ 84 | 'id' => 'survey-pjax', 85 | 'enablePushState' => false, 86 | 'timeout' => 0, 87 | 'scrollTo' => false, 88 | 'clientOptions' => [ 89 | 'type' => 'post', 90 | 'skipOuterContainers' => true, 91 | ] 92 | ]); 93 | 94 | $form = ActiveForm::begin([ 95 | 'id' => 'survey-form', 96 | 'action' => Url::toRoute(['default/update', 'id' => $survey->survey_id]), 97 | 'options' => ['class' => 'form-inline', 'data-pjax' => true], 98 | 'enableClientValidation' => false, 99 | 'enableAjaxValidation' => false, 100 | 'fieldConfig' => [ 101 | 'template' => "
{label}{input}\n{error}
", 102 | 'labelOptions' => ['class' => ''], 103 | ], 104 | ]); 105 | 106 | echo Html::beginTag('div', ['class' => 'row']); 107 | echo Html::beginTag('div', ['class' => 'col-md-12']); 108 | echo $form->field($survey, "survey_descr", ['template' => "
{label}{input}
",] 109 | )->textarea(['rows' => 3]); 110 | echo Html::tag('div', '', ['class' => 'clearfix']); 111 | echo Html::endTag('div'); 112 | echo Html::endTag('div'); 113 | 114 | echo Html::beginTag('div', ['class' => 'row']); 115 | echo Html::beginTag('div', ['class' => 'col-md-3']); 116 | echo $form->field($survey, "survey_is_closed", ['template' => "
{input}{label}
",] 117 | )->checkbox(['class' => 'checkbox danger'], false); 118 | echo Html::tag('div', '', ['class' => 'clearfix']); 119 | echo $form->field($survey, "survey_is_pinned", ['template' => "
{input}{label}
",] 120 | )->checkbox(['class' => 'checkbox'], false); 121 | echo Html::tag('div', '', ['class' => 'clearfix']); 122 | echo $form->field($survey, "survey_is_visible", ['template' => "
{input}{label}
",] 123 | )->checkbox(['class' => 'checkbox'], false); 124 | if ($withUserSearch) { 125 | echo Html::tag('div', '', ['class' => 'clearfix']); 126 | echo $form->field($survey, 127 | "survey_is_private", 128 | ['template' => "
{input}{label}
",] 129 | )->checkbox(['class' => 'checkbox danger'], false); 130 | } 131 | echo Html::endTag('div'); 132 | 133 | echo Html::beginTag('div', ['class' => 'col-md-9']); 134 | echo $form->field($survey, "survey_tags")->input('text', ['placeholder' => 'Comma separated']); 135 | echo Html::endTag('div'); 136 | echo Html::endTag('div'); 137 | 138 | echo Html::submitButton('', ['class' => 'hidden']); 139 | echo Html::tag('div', '', ['class' => 'clearfix']); 140 | 141 | ActiveForm::end(); 142 | 143 | Pjax::end(); 144 | ?> 145 | 146 |
147 | 148 |
149 |
150 |
151 | 152 |
153 | questions as $i => $question) { 155 | echo $this->render('/question/_viewForm', ['question' => $question, 'number' => $i]); 156 | } 157 | ?> 158 |
159 |
160 |
161 |
162 | 163 |
164 |
×
165 | survey_id; 168 | 169 | echo $this->render('respondents', 170 | compact('searchModel', 'dataProvider', 'surveyId', 'withUserSearch')); 171 | ?> 172 |
173 | 174 |
175 |
×
176 | survey_id; 179 | 180 | echo $this->render('restrictedUsers', 181 | compact('searchModel', 'restrictedUserDataProvider', 'surveyId', 'withUserSearch')); 182 | ?> 183 |
184 | 185 | registerJs(<<registerJs(<< 'survey-questions-pjax-' . $question->survey_question_id, 26 | 'enablePushState' => false, 27 | 'timeout' => 0, 28 | 'scrollTo' => false, 29 | 'options' => ['class' => 'survey-question-pjax-container'], 30 | // 'reloadCss' => false, 31 | 'clientOptions' => [ 32 | 'type' => 'post', 33 | 'skipOuterContainers' => true, 34 | ] 35 | ]); 36 | 37 | $form = ActiveForm::begin([ 38 | 'id' => 'survey-questions-form-' . $question->survey_question_id, 39 | 'action' => Url::toRoute(['question/update-and-close', 'id' => $question->survey_question_id]), 40 | 'validationUrl' => Url::toRoute(['question/validate', 'id' => $question->survey_question_id]), 41 | 'options' => ['class' => 'form-inline', 'data-pjax' => true], 42 | 'enableClientValidation' => false, 43 | 'enableAjaxValidation' => true, 44 | 'fieldConfig' => [ 45 | 'template' => "
{label}{input}\n{error}
", 46 | 'labelOptions' => ['class' => ''], 47 | ], 48 | ]); 49 | 50 | echo Html::beginTag('div', ['class' => 'survey-block', 'id' => 'survey-question-' . $question->survey_question_id]); 51 | 52 | echo Html::beginTag('div', ['class' => 'survey-question-name-wrap']); 53 | 54 | echo $form->field($question, "[{$question->survey_question_id}]survey_question_name")->input('text', ['placeholder' => \Yii::t('survey', 'Enter question name')])->label(false); 55 | 56 | echo Html::a(\Yii::t('survey', ''), Url::toRoute(['question/delete', 'id' => $question->survey_question_id]), [ 57 | 'class' => 'btn btn-danger pull-right btn-delete', 58 | ]); 59 | echo Html::submitButton('', ['class' => 'btn btn-success pull-right btn-save-question']); 60 | echo Html::submitButton('', ['class' => 'hidden update-question-btn survey-question-submit', 'data-action' => Url::toRoute(['question/update', 'id' => $question->survey_question_id])]); 61 | echo Html::endTag('div'); 62 | 63 | $confirmMessage = \Yii::t('survey', 'Current types are not compatible, all entered data will be deleted. Are you sure?'); 64 | echo $form->field($question, "[{$question->survey_question_id}]survey_question_type")->widget(Select2::classname(), [ 65 | 'data' => \onmotion\survey\models\SurveyType::getDropdownList(), 66 | 'pluginOptions' => [ 67 | 'allowClear' => false 68 | ], 69 | 'pluginEvents' => [ 70 | 71 | "select2:selecting" => new \yii\web\JsExpression(<< new \yii\web\JsExpression(<<field($question, "[{$question->survey_question_id}]survey_question_show_descr")->checkbox(['class' => 'checkbox-updatable']); 111 | echo Html::tag('br', ''); 112 | 113 | if ($question->survey_question_show_descr) { 114 | echo $form->field($question, "[{$question->survey_question_id}]survey_question_descr")->widget(Widget::class, [ 115 | 'settings' => [ 116 | 'lang' => 'ru', 117 | 'minHeight' => 200, 118 | 'toolbarFixed' => false, 119 | 'imageManagerJson' => Url::toRoute(['question/images-get']), 120 | 'imageUpload' => Url::toRoute(['question/image-upload']), 121 | 'fileManagerJson' => Url::toRoute(['question/files-get']), 122 | 'fileUpload' => Url::toRoute(['question/file-upload']), 123 | 'plugins' => [ 124 | 'imagemanager', 125 | 'video', 126 | 'fullscreen', 127 | 'filemanager', 128 | 'fontsize', 129 | 'fontcolor', 130 | 'table', 131 | ] 132 | ] 133 | ])->label(false); 134 | } 135 | 136 | echo Html::beginTag('div', ['class' => 'answers-container', 'id' => 'survey-answers-' . $question->survey_question_id]); 137 | if (isset($question->survey_question_type)) { 138 | echo $this->render('/answers/_form', ['question' => $question, 'form' => $form]); 139 | } 140 | 141 | echo Html::endTag('div'); 142 | 143 | echo Html::tag('hr', ''); 144 | echo $form->field($question, "[{$question->survey_question_id}]survey_question_can_skip")->checkbox(); 145 | if (in_array($question->survey_question_type, [ 146 | SurveyType::TYPE_MULTIPLE, 147 | SurveyType::TYPE_ONE_OF_LIST, 148 | SurveyType::TYPE_DROPDOWN 149 | ])) { 150 | echo Html::tag('br', ''); 151 | echo $form->field($question, "[{$question->survey_question_id}]survey_question_is_scorable")->checkbox(['class' => 'checkbox-updatable']); 152 | } 153 | ?> 154 |
155 |
156 |
157 | 'survey-block', 'id' => 'survey-question-' . $question->survey_question_id]); 27 | 28 | echo Html::beginTag('div', ['class' => 'survey-question-name-wrap']); 29 | echo ($number + 1) . '. ' . $question->survey_question_name; 30 | echo Html::endTag('div'); 31 | 32 | 33 | echo Html::beginTag('div', ['class' => 'survey-question-descr-wrap']); 34 | if ($question->survey_question_show_descr) { 35 | echo $question->survey_question_descr; 36 | } 37 | echo Html::endTag('div'); 38 | 39 | 40 | echo Html::beginTag('div', ['class' => 'answers-container', 'id' => 'survey-answers-' . $question->survey_question_id]); 41 | if (isset($question->survey_question_type)) { 42 | echo $this->render('/answers/view/_form', ['question' => $question]); 43 | } 44 | 45 | echo Html::endTag('div'); 46 | 47 | echo Html::tag('hr', ''); 48 | 49 | ?> 50 |
51 |
52 |
53 | 'survey-questions-pjax-' . $question->survey_question_id, 20 | 'enablePushState' => false, 21 | 'timeout' => 0, 22 | 'scrollTo' => false, 23 | 'clientOptions' => [ 24 | 'type' => 'post', 25 | 'skipOuterContainers' => true, 26 | ] 27 | ]); 28 | 29 | echo Html::beginTag('div', ['class' => 'survey-block', 'id' => 'survey-question-' . $question->survey_question_id]); 30 | echo Html::beginTag('div', ['class' => 'survey-question-view-wrap']); 31 | 32 | echo Html::tag('h4', $question->survey_question_name); 33 | 34 | echo Html::a(\Yii::t('survey', ''), Url::toRoute(['question/edit', 'id' => $question->survey_question_id]), [ 35 | 'class' => 'btn btn-info pull-right btn-edit', 36 | ]); 37 | echo Html::endTag('div'); 38 | echo Html::endTag('div'); 39 | 40 | Pjax::end(); -------------------------------------------------------------------------------- /views/widget/answers/1.php: -------------------------------------------------------------------------------- 1 | userAnswers; 19 | 20 | foreach ($question->answers as $i => $answer) { 21 | $userAnswer = $userAnswers[$answer->survey_answer_id] ?? (new SurveyUserAnswer()); 22 | 23 | $label = '
' . $answer->survey_answer_name . '
'; 24 | 25 | 26 | if ($answer->survey_answer_show_descr) { 27 | $label .= "
$answer->survey_answer_descr
"; 28 | } 29 | $label .= '
'; 30 | 31 | echo $form->field($userAnswer, "[$question->survey_question_id][$answer->survey_answer_id]survey_user_answer_value", 32 | [ 33 | 'template' => "
{input}{label}
\n{hint}\n{error}", 34 | 'labelOptions' => ['class' => 'css-label', 'label' => $label], 35 | ] 36 | )->checkbox(['class' => 'css-checkbox', 'disabled' => $readonly], false); 37 | 38 | echo Html::tag('br', ''); 39 | } -------------------------------------------------------------------------------- /views/widget/answers/10.php: -------------------------------------------------------------------------------- 1 | userAnswers; 19 | 20 | $ddList = [ 21 | 1 => \Yii::t('survey', 'Available'), 22 | 2 => \Yii::t('survey', 'Unavailable'), 23 | 3 => \Yii::t('survey', 'If needed'), 24 | ]; 25 | 26 | foreach ($question->answers as $i => $answer) { 27 | $userAnswer = $userAnswers[$answer->survey_answer_id] ?? (new SurveyUserAnswer()); 28 | 29 | $label = '
' . $answer->survey_answer_name . '
'; 30 | 31 | if ($answer->survey_answer_show_descr) { 32 | $label .= '
' . $answer->survey_answer_descr; 33 | } 34 | $label .= '
'; 35 | 36 | echo Html::beginTag('div', ['class' => 'answer-item']); 37 | 38 | echo Html::tag('div', $form->field($userAnswer, "[$question->survey_question_id][$answer->survey_answer_id]survey_user_answer_value",[ 39 | 'template' => "{input}{label}\n{hint}\n{error}", 40 | ]) 41 | ->dropDownList($ddList, ['encode' => false, 'prompt' => \Yii::t('survey', 'Select...'), 'disabled' => $readonly])->label(false)); 42 | echo $label; 43 | echo Html::endTag('div'); 44 | 45 | // echo Html::tag('br', ''); 46 | } -------------------------------------------------------------------------------- /views/widget/answers/2.php: -------------------------------------------------------------------------------- 1 | userAnswers; 18 | $userAnswer = !empty(current($userAnswers)) ? current($userAnswers) : (new SurveyUserAnswer()); 19 | $radioList = []; 20 | 21 | foreach ($question->answers as $i => $answer) { 22 | 23 | $radioList[$answer->survey_answer_id] = '
' . $answer->survey_answer_name . '
'; 24 | if ($answer->survey_answer_show_descr) { 25 | $radioList[$answer->survey_answer_id] .= '
' . $answer->survey_answer_descr; 26 | } 27 | $radioList[$answer->survey_answer_id] .= '
'; 28 | } 29 | 30 | echo $form->field($userAnswer, "[$question->survey_question_id]survey_user_answer_value", 31 | ['template' => "
{label}{input}
\n{hint}\n{error}"]) 32 | ->radioList($radioList, ['encode' => false, 33 | 'item' => function ($index, $label, $name, $checked, $value) use ($readonly) { 34 | $id = uniqid('radio-'); 35 | return Html::radio($name, $checked, ['value' => $value, 'class' => 'css-radio', 'id' => $id, 'disabled' => $readonly]) . "'; 36 | } 37 | ])->label(false); 38 | 39 | echo Html::tag('br', ''); -------------------------------------------------------------------------------- /views/widget/answers/3.php: -------------------------------------------------------------------------------- 1 | userAnswers; 17 | $userAnswer = !empty(current($userAnswers)) ? current($userAnswers) : (new SurveyUserAnswer()) ; 18 | $ddList = []; 19 | 20 | foreach ($question->answers as $i => $answer) { 21 | $ddList[$answer->survey_answer_id] = $answer->survey_answer_name; 22 | } 23 | 24 | echo $form->field($userAnswer, "[$question->survey_question_id]survey_user_answer_value")->dropDownList($ddList, 25 | ['encode' => false, 'prompt' => \Yii::t('survey', 'Select...'), 'disabled' => $readonly])->label(false); 26 | echo Html::tag('div', '', ['class' => 'clearfix']); -------------------------------------------------------------------------------- /views/widget/answers/4.php: -------------------------------------------------------------------------------- 1 | userAnswers; 19 | 20 | $ddList = []; 21 | for ($i = 1, $answersCnt = count($question->answers); $i <= $answersCnt; ++$i){ 22 | $ddList[$i] = $i; 23 | } 24 | 25 | foreach ($question->answers as $i => $answer) { 26 | $userAnswer = $userAnswers[$answer->survey_answer_id] ?? (new SurveyUserAnswer()); 27 | 28 | $label = '
' . $answer->survey_answer_name . '
'; 29 | 30 | if ($answer->survey_answer_show_descr) { 31 | $label .= '
' . $answer->survey_answer_descr; 32 | } 33 | $label .= '
'; 34 | 35 | echo Html::beginTag('div', ['class' => 'answer-item']); 36 | 37 | echo Html::tag('div', $form->field($userAnswer, "[$question->survey_question_id][$answer->survey_answer_id]survey_user_answer_value",[ 38 | 'template' => "{input}{label}\n{hint}\n{error}", 39 | ]) 40 | ->dropDownList($ddList, ['encode' => false, 'prompt' => \Yii::t('survey', 'Select...'), 'disabled' => $readonly])->label(false)); 41 | echo $label; 42 | echo Html::endTag('div'); 43 | 44 | // echo Html::tag('br', ''); 45 | } -------------------------------------------------------------------------------- /views/widget/answers/5.php: -------------------------------------------------------------------------------- 1 | userAnswers; 20 | $userAnswer = !empty(current($userAnswers)) ? current($userAnswers) : (new SurveyUserAnswer()); 21 | $min = isset($question->answers[0]->survey_answer_name) ? intval($question->answers[0]->survey_answer_name) : 0; 22 | $max = isset($question->answers[1]->survey_answer_name) ? intval($question->answers[1]->survey_answer_name) : 100; 23 | 24 | $userAnswer->survey_user_answer_value = intval($userAnswer->survey_user_answer_value); 25 | 26 | echo $form->field($userAnswer, "[$question->survey_question_id]survey_user_answer_value", 27 | ['template' => '
' . $min . ' ' . $max . '
' . "{label}{input}\n{error}
"])->widget(Slider::classname(), [ 28 | 'id' => 'slider', 29 | 'sliderColor' => Slider::TYPE_GREY, 30 | 'pluginOptions' => [ 31 | 'min' => $min, 32 | 'max' => $max, 33 | 'now' => 0, 34 | 'step' => 1, 35 | 'range' => false, 36 | ], 37 | 'options' => [ 38 | 'disabled' => $readonly, 39 | ], 40 | ])->label(false); 41 | 42 | -------------------------------------------------------------------------------- /views/widget/answers/6.php: -------------------------------------------------------------------------------- 1 | userAnswers; 20 | $userAnswer = !empty(current($userAnswers)) ? current($userAnswers) : (new SurveyUserAnswer()) ; 21 | 22 | echo $form->field($userAnswer, "[$question->survey_question_id]survey_user_answer_value")->textInput( 23 | ['placeholder' => \Yii::t('survey', 'Enter your answer here'), 'disabled' => $readonly])->label(\Yii::t('survey', 'Answer')); 24 | 25 | -------------------------------------------------------------------------------- /views/widget/answers/7.php: -------------------------------------------------------------------------------- 1 | userAnswers; 19 | 20 | foreach ($question->answers as $i => $answer) { 21 | $userAnswer = $userAnswers[$answer->survey_answer_id] ?? (new SurveyUserAnswer()); 22 | 23 | echo $form->field($userAnswer, "[$question->survey_question_id][$answer->survey_answer_id]survey_user_answer_value")->input('text', 24 | ['placeholder' => \Yii::t('survey', 'Enter your answer here'), 'disabled' => $readonly])->label($answer->survey_answer_name); 25 | 26 | echo Html::tag('div', '', ['class' => 'clearfix']); 27 | } -------------------------------------------------------------------------------- /views/widget/answers/8.php: -------------------------------------------------------------------------------- 1 | userAnswers; 20 | $userAnswer = !empty(current($userAnswers)) ? current($userAnswers) : (new SurveyUserAnswer()) ; 21 | 22 | echo $form->field($userAnswer, "[$question->survey_question_id]survey_user_answer_text")->textarea( 23 | ['placeholder' => \Yii::t('survey', 'Enter your answer here'), 'rows' => 6, 'disabled' => $readonly])->label(\Yii::t('survey', 'Answer')); 24 | 25 | -------------------------------------------------------------------------------- /views/widget/answers/9.php: -------------------------------------------------------------------------------- 1 | userAnswers; 20 | 21 | foreach ($question->answers as $i => $answer) { 22 | $userAnswer = $userAnswers[$answer->survey_answer_id] ?? (new SurveyUserAnswer()); 23 | 24 | echo $form->field($userAnswer, "[$question->survey_question_id][$answer->survey_answer_id]survey_user_answer_value", 25 | [ 26 | 'template' => "
{input}{label}\n{hint}\n{error}
", 27 | 'labelOptions' => ['class' => 'css-label answer-text'], 28 | ] 29 | )->widget(DatePicker::classname(), [ 30 | 'options' => ['placeholder' => 'Enter event time ...'], 31 | 'removeButton' => false, 32 | 'disabled' => $readonly, 33 | 'pluginOptions' => [ 34 | 'format' => 'dd-MM-yyyy', 35 | 'autoclose' => true 36 | ] 37 | ])->label($answer->survey_answer_name); 38 | // echo Html::label($answer->survey_answer_name); 39 | 40 | echo Html::tag('div', '', ['class' => 'clearfix']); 41 | } -------------------------------------------------------------------------------- /views/widget/answers/_form.php: -------------------------------------------------------------------------------- 1 | render('@surveyRoot/views/widget/answers/' . $question->survey_question_type, ['question' => $question, 'form' => $form, 'readonly' => $readonly]); -------------------------------------------------------------------------------- /views/widget/default/closed.php: -------------------------------------------------------------------------------- 1 | 20 | 21 |

22 | 23 | 24 | -------------------------------------------------------------------------------- /views/widget/default/index.php: -------------------------------------------------------------------------------- 1 | survey_stat_is_done) { 28 | $status = 'Completed'; 29 | $statusClass = 'is-done'; 30 | } else { 31 | $statusClass = $survey->getStatus(); 32 | switch ($statusClass) { 33 | case 'active': 34 | $status = 'Active'; 35 | break; 36 | case 'expired': 37 | $status = 'Expired'; 38 | break; 39 | case 'closed': 40 | $status = 'Closed'; 41 | break; 42 | default: 43 | $status = 'undefined'; 44 | break; 45 | } 46 | } 47 | ?> 48 | 49 |
50 |
51 |
52 | 53 |
54 |
55 |

survey_name; ?>

56 | survey_descr)) { 58 | echo "
$survey->survey_descr
"; 59 | } 60 | ?> 61 |
62 | 63 |
64 | questions as $i => $question) { 66 | echo $this->render('@surveyRoot/views/widget/question/_form', [ 67 | 'question' => $question, 68 | 'number' => $i, 69 | 'readonly' => $statusClass !== 'active' 70 | ]); 71 | } 72 | ?> 73 |
74 |
75 |
76 | 77 |
78 | 121 | 122 |
123 | 'btn btn-success center-block', 'data-default-text' => \Yii::t('survey', 'Done'), 128 | 'id' => 's-done', 'data-action' => Url::toRoute(['/survey/default/done']), 'data-hash' => $stat->survey_stat_hash]); 129 | } 130 | ?> 131 |
132 | registerJs(<<survey_id}); 137 | }); 138 | JS 139 | ); -------------------------------------------------------------------------------- /views/widget/default/success.php: -------------------------------------------------------------------------------- 1 | 17 | 18 |

19 | 20 |

21 | 22 | -------------------------------------------------------------------------------- /views/widget/default/unavailable.php: -------------------------------------------------------------------------------- 1 | 20 | 21 |

22 | 23 | 24 | -------------------------------------------------------------------------------- /views/widget/question/_form.php: -------------------------------------------------------------------------------- 1 | 'survey-questions-pjax-' . $question->survey_question_id, 28 | 'enablePushState' => false, 29 | 'timeout' => 0, 30 | 'scrollTo' => false, 31 | 'options' => ['class' => 'survey-question-pjax-container'], 32 | 'clientOptions' => [ 33 | 'type' => 'post', 34 | 'skipOuterContainers' => true, 35 | // 'async' => false, 36 | ] 37 | ]); 38 | 39 | $form = ActiveForm::begin([ 40 | 'id' => 'survey-questions-form-' . $question->survey_question_id, 41 | 'action' => Url::toRoute(['/survey/question/submit-answer', 'id' => $question->survey_question_id, 'n' => $number]), 42 | 'validationUrl' => Url::toRoute(['/survey/question/validate', 'id' => $question->survey_question_id]), 43 | 'options' => ['class' => 'form-inline question-form', 'data-pjax' => true], 44 | 'enableClientValidation' => false, 45 | 'enableAjaxValidation' => true, 46 | 'validateOnBlur' => false, 47 | 'validateOnSubmit' => true, 48 | 'fieldConfig' => [ 49 | 'template' => "
{label}{input}\n{error}
", 50 | 'labelOptions' => ['class' => ''], 51 | ], 52 | ]); 53 | 54 | echo Html::beginTag('div', ['class' => 'survey-block', 'id' => 'survey-question-' . $question->survey_question_id]); 55 | 56 | echo Html::beginTag('div', ['class' => 'survey-question-name-wrap']); 57 | echo Html::tag('h4', ($number + 1) . '. ' . $question->survey_question_name); 58 | echo Html::endTag('div'); 59 | 60 | if ($question->survey_question_show_descr) { 61 | echo Html::beginTag('div', ['class' => 'survey-question-descr-wrap']); 62 | echo $question->survey_question_descr; 63 | echo Html::endTag('div'); 64 | } 65 | 66 | 67 | echo Html::beginTag('div', ['class' => 'answers-container', 'id' => 'survey-answers-' . $question->survey_question_id]); 68 | if (isset($question->survey_question_type)) { 69 | echo $this->render('@surveyRoot/views/widget/answers/_form', ['question' => $question, 'form' => $form, 'readonly' => $readonly]); 70 | } 71 | 72 | echo Html::endTag('div'); 73 | 74 | echo Html::tag('div', Html::submitButton('DONE', ['class' => 'btn btn-primary btn-submit hidden animated']), ['class' => 'card-footer']); 75 | 76 | //echo $form->errorSummary([$question]); 77 | 78 | ?> 79 |
80 |
81 |
82 | userAnswers; 39 | if ($question->survey_question_type === SurveyType::TYPE_MULTIPLE 40 | || $question->survey_question_type === SurveyType::TYPE_RANKING 41 | || $question->survey_question_type === SurveyType::TYPE_MULTIPLE_TEXTBOX 42 | || $question->survey_question_type === SurveyType::TYPE_CALENDAR 43 | ) { 44 | if (count($userAnswers) < 2) { 45 | return false; 46 | } 47 | foreach ($question->answers as $i => $answer) { 48 | $userAnswer = $userAnswers[$answer->survey_answer_id]; 49 | $userAnswer->validate(); 50 | foreach ($userAnswer->getErrors() as $attribute => $errors) { 51 | return false; 52 | } 53 | $question->validateMultipleAnswer(); 54 | foreach ($question->userAnswers as $userAnswer) { 55 | foreach ($userAnswer->getErrors() as $attribute => $errors) { 56 | return false; 57 | } 58 | } 59 | } 60 | } elseif ($question->survey_question_type === SurveyType::TYPE_ONE_OF_LIST 61 | || $question->survey_question_type === SurveyType::TYPE_DROPDOWN 62 | || $question->survey_question_type === SurveyType::TYPE_SLIDER 63 | || $question->survey_question_type === SurveyType::TYPE_SINGLE_TEXTBOX 64 | || $question->survey_question_type === SurveyType::TYPE_COMMENT_BOX 65 | || $question->survey_question_type === SurveyType::TYPE_DATE_TIME 66 | ) { 67 | if (empty(current($userAnswers))) { 68 | return false; 69 | } 70 | $userAnswer = current($userAnswers); 71 | $userAnswer->validate(); 72 | foreach ($userAnswer->getErrors() as $attribute => $errors) { 73 | return false; 74 | } 75 | } 76 | 77 | return true; 78 | } 79 | 80 | public function actionDone() 81 | { 82 | $id = \Yii::$app->request->post('id'); 83 | if ($id < 0) { 84 | throw new UserException('Wrong survey id defined'); 85 | } 86 | $survey = $this->findModel($id); 87 | $stat = SurveyStat::findOne(['survey_stat_survey_id' => $id, 'survey_stat_user_id' => \Yii::$app->user->getId()]); 88 | if ($stat === null) { 89 | throw new UserException('The requested survey stat does not exist.'); 90 | } elseif ($stat->survey_stat_is_done) { 91 | throw new UserException('The survey has already been completed.'); 92 | } 93 | foreach ($survey->questions as $question) { 94 | if (!$this->validateQuestion($question)) { 95 | throw new UserException('An error has been occurred during validating.'); 96 | } 97 | } 98 | //all validation is passed. 99 | $stat->survey_stat_is_done = true; 100 | $stat->survey_stat_ended_at = new Expression("NOW()"); 101 | $stat->save(false); 102 | 103 | \Yii::$app->response->format = Response::FORMAT_JSON; 104 | return [ 105 | 'title' => '

' . \Yii::t('survey', 'Thank you!'), 106 | 'content' => $this->renderPartial('@surveyRoot/views/widget/default/success', ['survey' => $survey]), 107 | 'footer' => 108 | Html::button('Ok', ['class' => 'btn btn-default pull-left', 'data-dismiss' => "modal"]) 109 | ]; 110 | } 111 | 112 | protected function findModel($id) 113 | { 114 | if (($model = Survey::findOne($id)) !== null) { 115 | return $model; 116 | } else { 117 | throw new NotFoundHttpException('The requested page does not exist.'); 118 | } 119 | } 120 | 121 | 122 | } 123 | -------------------------------------------------------------------------------- /widgetControllers/QuestionController.php: -------------------------------------------------------------------------------- 1 | user->getId(), $question->survey->survey_id); 38 | //не работаем с завершенными опросами 39 | if ($stat->survey_stat_is_done) { 40 | return false; 41 | } 42 | $post = \Yii::$app->request->post(); 43 | 44 | $result = []; 45 | 46 | \Yii::$app->response->format = Response::FORMAT_JSON; 47 | 48 | $answersData = ArrayHelper::getValue($post, "SurveyUserAnswer.{$question->survey_question_id}"); 49 | $userAnswers = $question->userAnswers; 50 | 51 | if (!empty($answersData)) { 52 | if ($question->survey_question_type === SurveyType::TYPE_MULTIPLE 53 | || $question->survey_question_type === SurveyType::TYPE_RANKING 54 | || $question->survey_question_type === SurveyType::TYPE_MULTIPLE_TEXTBOX 55 | || $question->survey_question_type === SurveyType::TYPE_DATE_TIME 56 | || $question->survey_question_type === SurveyType::TYPE_CALENDAR 57 | ) { 58 | foreach ($question->answers as $i => $answer) { 59 | if (!$question->survey->isAccessibleByCurrentUser) { 60 | die(['lkj']); 61 | } 62 | 63 | $userAnswer = isset($userAnswers[$answer->survey_answer_id]) ? $userAnswers[$answer->survey_answer_id] : (new SurveyUserAnswer([ 64 | 'survey_user_answer_user_id' => \Yii::$app->user->getId(), 65 | 'survey_user_answer_survey_id' => $question->survey_question_survey_id, 66 | 'survey_user_answer_question_id' => $question->survey_question_id, 67 | 'survey_user_answer_answer_id' => $answer->survey_answer_id 68 | ])); 69 | if ($userAnswer->load($answersData[$answer->survey_answer_id], '')) { 70 | $userAnswer->validate(); 71 | foreach ($userAnswer->getErrors() as $attribute => $errors) { 72 | $result["surveyuseranswer-{$question->survey_question_id}-{$answer->survey_answer_id}-{$attribute}"] = $errors; 73 | } 74 | $userAnswer->save(); 75 | } 76 | } 77 | $question->refresh(); 78 | $question->validateMultipleAnswer(); 79 | foreach ($question->userAnswers as $userAnswer) { 80 | foreach ($userAnswer->getErrors() as $attribute => $errors) { 81 | $result["surveyuseranswer-{$question->survey_question_id}-{$userAnswer->survey_user_answer_answer_id}-{$attribute}"] = $errors; 82 | } 83 | } 84 | } elseif ($question->survey_question_type === SurveyType::TYPE_ONE_OF_LIST 85 | || $question->survey_question_type === SurveyType::TYPE_DROPDOWN 86 | || $question->survey_question_type === SurveyType::TYPE_SLIDER 87 | || $question->survey_question_type === SurveyType::TYPE_SINGLE_TEXTBOX 88 | || $question->survey_question_type === SurveyType::TYPE_COMMENT_BOX 89 | ) { 90 | $userAnswer = !empty(current($userAnswers)) ? current($userAnswers) : (new SurveyUserAnswer([ 91 | 'survey_user_answer_user_id' => \Yii::$app->user->getId(), 92 | 'survey_user_answer_survey_id' => $question->survey_question_survey_id, 93 | 'survey_user_answer_question_id' => $question->survey_question_id, 94 | ])); 95 | if ($userAnswer->load($answersData, '')) { 96 | $userAnswer->validate(); 97 | foreach ($userAnswer->getErrors() as $attribute => $errors) { 98 | $result["surveyuseranswer-{$question->survey_question_id}-{$attribute}"] = $errors; 99 | } 100 | $userAnswer->save(); 101 | } 102 | } 103 | } 104 | 105 | return $result; 106 | } 107 | 108 | public function actionValidate($id) 109 | { 110 | $question = $this->findModel($id); 111 | return $this->validate($question); 112 | } 113 | 114 | public function actionSubmitAnswer($id, $n) 115 | { 116 | $question = $this->findModel($id); 117 | $this->validate($question); 118 | 119 | return $this->renderAjax('@surveyRoot/views/widget/question/_form', ['question' => $question, 'number' => $n]); 120 | } 121 | 122 | 123 | protected function findModel($id) 124 | { 125 | if (($model = SurveyQuestion::findOne($id)) !== null) { 126 | return $model; 127 | } else { 128 | throw new NotFoundHttpException('The requested page does not exist.'); 129 | } 130 | } 131 | 132 | protected function findSurveyModel($id) 133 | { 134 | if (($model = Survey::findOne($id)) !== null) { 135 | return $model; 136 | } else { 137 | throw new NotFoundHttpException('The requested page does not exist.'); 138 | } 139 | } 140 | 141 | protected function findTypeModel($id) 142 | { 143 | if (($model = SurveyType::findOne($id)) !== null) { 144 | return $model; 145 | } else { 146 | throw new NotFoundHttpException('The requested page does not exist.'); 147 | } 148 | } 149 | } 150 | --------------------------------------------------------------------------------