├── .bowerrc
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── LICENSE.md
├── README.md
├── backend
├── assets
│ └── AppAsset.php
├── config
│ ├── .gitignore
│ ├── bootstrap.php
│ ├── main.php
│ └── params.php
├── controllers
│ ├── CategoryController.php
│ ├── ProductController.php
│ └── SiteController.php
├── models
│ ├── .gitkeep
│ ├── CategorySearch.php
│ └── ProductSearch.php
├── runtime
│ └── .gitignore
├── views
│ ├── category
│ │ ├── _form.php
│ │ ├── _search.php
│ │ ├── create.php
│ │ ├── index.php
│ │ ├── update.php
│ │ └── view.php
│ ├── layouts
│ │ └── main.php
│ ├── product
│ │ ├── _form.php
│ │ ├── _search.php
│ │ ├── create.php
│ │ ├── index.php
│ │ ├── update.php
│ │ └── view.php
│ └── site
│ │ ├── error.php
│ │ ├── index.php
│ │ └── login.php
└── web
│ ├── .gitignore
│ ├── .htaccess
│ ├── assets
│ └── .gitignore
│ ├── css
│ └── site.css
│ ├── favicon.ico
│ └── robots.txt
├── common
├── components
│ └── Catalog.php
├── config
│ ├── .gitignore
│ ├── bootstrap.php
│ ├── main.php
│ └── params.php
├── mail
│ ├── layouts
│ │ └── html.php
│ └── passwordResetToken.php
└── models
│ ├── Category.php
│ ├── LoginForm.php
│ ├── Product.php
│ └── User.php
├── composer.json
├── console
├── config
│ ├── .gitignore
│ ├── bootstrap.php
│ ├── main.php
│ └── params.php
├── controllers
│ └── .gitkeep
├── migrations
│ ├── m130524_201442_init.php
│ ├── m141109_104615_create_products.php
│ ├── m141109_111923_create_categories.php
│ └── m141113_155131_create_category_product.php
├── models
│ └── .gitkeep
└── runtime
│ └── .gitignore
├── environments
├── dev
│ ├── backend
│ │ ├── config
│ │ │ ├── main-local.php
│ │ │ └── params-local.php
│ │ └── web
│ │ │ ├── index-test.php
│ │ │ └── index.php
│ ├── common
│ │ └── config
│ │ │ ├── main-local.php
│ │ │ └── params-local.php
│ ├── console
│ │ └── config
│ │ │ ├── main-local.php
│ │ │ └── params-local.php
│ ├── frontend
│ │ ├── config
│ │ │ ├── main-local.php
│ │ │ └── params-local.php
│ │ └── web
│ │ │ ├── index-test.php
│ │ │ └── index.php
│ └── yii
├── index.php
└── prod
│ ├── backend
│ ├── config
│ │ ├── main-local.php
│ │ └── params-local.php
│ └── web
│ │ └── index.php
│ ├── common
│ └── config
│ │ ├── main-local.php
│ │ └── params-local.php
│ ├── console
│ └── config
│ │ ├── main-local.php
│ │ └── params-local.php
│ ├── frontend
│ ├── config
│ │ ├── main-local.php
│ │ └── params-local.php
│ └── web
│ │ └── index.php
│ └── yii
├── frontend
├── assets
│ └── AppAsset.php
├── config
│ ├── .gitignore
│ ├── bootstrap.php
│ ├── main.php
│ └── params.php
├── controllers
│ ├── CategoryController.php
│ └── SiteController.php
├── models
│ ├── ContactForm.php
│ ├── PasswordResetRequestForm.php
│ ├── ResetPasswordForm.php
│ └── SignupForm.php
├── runtime
│ └── .gitignore
├── views
│ ├── category
│ │ ├── index.php
│ │ └── view.php
│ ├── layouts
│ │ └── main.php
│ └── site
│ │ ├── about.php
│ │ ├── contact.php
│ │ ├── error.php
│ │ ├── index.php
│ │ ├── login.php
│ │ ├── product.php
│ │ ├── requestPasswordResetToken.php
│ │ ├── resetPassword.php
│ │ └── signup.php
├── web
│ ├── .gitignore
│ ├── .htaccess
│ ├── assets
│ │ └── .gitignore
│ ├── css
│ │ └── site.css
│ ├── favicon.ico
│ └── robots.txt
└── widgets
│ ├── Alert.php
│ ├── CategoriesList.php
│ └── views
│ └── categories-list.php
├── init
├── requirements.php
└── tests
├── README.md
├── codeception.yml
└── codeception
├── _output
└── .gitignore
├── backend
├── .gitignore
├── _bootstrap.php
├── _output
│ └── .gitignore
├── acceptance.suite.yml
├── acceptance
│ ├── LoginCept.php
│ └── _bootstrap.php
├── codeception.yml
├── functional.suite.yml
├── functional
│ ├── LoginCept.php
│ └── _bootstrap.php
├── unit.suite.yml
└── unit
│ ├── DbTestCase.php
│ ├── TestCase.php
│ ├── _bootstrap.php
│ └── fixtures
│ └── data
│ └── .gitkeep
├── bin
├── _bootstrap.php
├── yii
└── yii.bat
├── common
├── .gitignore
├── _bootstrap.php
├── _output
│ └── .gitignore
├── _pages
│ └── LoginPage.php
├── _support
│ └── FixtureHelper.php
├── codeception.yml
├── fixtures
│ ├── UserFixture.php
│ └── data
│ │ └── init_login.php
├── templates
│ └── fixtures
│ │ └── user.php
├── unit.suite.yml
└── unit
│ ├── DbTestCase.php
│ ├── TestCase.php
│ ├── _bootstrap.php
│ ├── fixtures
│ └── data
│ │ └── models
│ │ └── user.php
│ └── models
│ └── LoginFormTest.php
├── config
├── acceptance.php
├── backend
│ ├── acceptance.php
│ ├── config.php
│ ├── functional.php
│ └── unit.php
├── common
│ └── unit.php
├── config.php
├── console
│ └── unit.php
├── frontend
│ ├── acceptance.php
│ ├── config.php
│ ├── functional.php
│ └── unit.php
├── functional.php
└── unit.php
├── console
├── .gitignore
├── _bootstrap.php
├── _output
│ └── .gitignore
├── codeception.yml
├── unit.suite.yml
└── unit
│ ├── DbTestCase.php
│ ├── TestCase.php
│ ├── _bootstrap.php
│ └── fixtures
│ └── data
│ └── .gitkeep
└── frontend
├── .gitignore
├── _bootstrap.php
├── _output
└── .gitignore
├── _pages
├── AboutPage.php
├── ContactPage.php
└── SignupPage.php
├── acceptance.suite.yml
├── acceptance
├── AboutCept.php
├── ContactCept.php
├── HomeCept.php
├── LoginCept.php
├── SignupCest.php
└── _bootstrap.php
├── codeception.yml
├── functional.suite.yml
├── functional
├── AboutCept.php
├── ContactCept.php
├── HomeCept.php
├── LoginCept.php
├── SignupCest.php
└── _bootstrap.php
├── unit.suite.yml
└── unit
├── DbTestCase.php
├── TestCase.php
├── _bootstrap.php
├── fixtures
└── data
│ └── models
│ └── user.php
└── models
├── ContactFormTest.php
├── PasswordResetRequestFormTest.php
├── ResetPasswordFormTest.php
└── SignupFormTest.php
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory" : "vendor/bower"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # yii console command
2 | /yii
3 |
4 | # phpstorm project files
5 | .idea
6 |
7 | # netbeans project files
8 | nbproject
9 |
10 | # zend studio for eclipse project files
11 | .buildpath
12 | .project
13 | .settings
14 |
15 | # sublime text project files
16 | *.sublime-project
17 | *.sublime-workspace
18 |
19 | # windows thumbnail cache
20 | Thumbs.db
21 |
22 | # composer vendor dir
23 | /vendor
24 |
25 | # composer itself is not needed
26 | composer.phar
27 | composer.lock
28 |
29 | # Mac DS_Store Files
30 | .DS_Store
31 |
32 | # phpunit itself is not needed
33 | phpunit.phar
34 | # local phpunit config
35 | /phpunit.xml
36 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 |
4 | ## Unreleased
5 | ### Added
6 | - Hierarchical category tree: made change to FancytreeWidget, Fancytree.js. [See more](https://github.com/mar10/fancytree/pull/342)
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Serhiy Vinichuk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Serhiy Vinichuk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Yii 2 Shopper
2 | ===================================
3 |
4 | Yii 2 Shopper is a skeleton Yii 2 e-commerce application.
5 |
6 |
7 | REQUIREMENTS
8 | ------------
9 |
10 | The minimum requirement by this application template that your Web server supports PHP 5.4.0.
11 |
12 |
13 | GETTING STARTED
14 | ---------------
15 |
16 | After you install the application, you have to conduct the following steps to initialize
17 | the installed application. You only need to do these once for all.
18 |
19 | 1. Run command `init` to initialize the application with a specific environment.
20 | 2. Create a new database and adjust the `components['db']` configuration in `common/config/main-local.php` accordingly.
21 | 3. Apply migrations with console command `yii migrate`. This will create tables needed for the application to work.
22 | 4. Set document roots of your Web server:
23 |
24 | - for frontend `/path/to/yii-application/frontend/web/` and using the URL `http://frontend/`
25 | - for backend `/path/to/yii-application/backend/web/` and using the URL `http://backend/`
26 |
27 | To login into the application, you need to first sign up, with any of your email address, username and password.
28 | Then, you can login into the application with same email address and password at any time.
29 |
--------------------------------------------------------------------------------
/backend/assets/AppAsset.php:
--------------------------------------------------------------------------------
1 |
14 | * @since 2.0
15 | */
16 | class AppAsset extends AssetBundle
17 | {
18 | public $basePath = '@webroot';
19 | public $baseUrl = '@web';
20 | public $css = [
21 | 'css/site.css',
22 | ];
23 | public $js = [
24 | ];
25 | public $depends = [
26 | 'yii\web\YiiAsset',
27 | 'yii\bootstrap\BootstrapAsset',
28 | 'rmrevin\yii\fontawesome\AssetBundle',
29 | ];
30 | }
31 |
--------------------------------------------------------------------------------
/backend/config/.gitignore:
--------------------------------------------------------------------------------
1 | main-local.php
2 | params-local.php
--------------------------------------------------------------------------------
/backend/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | 'app-backend',
11 | 'basePath' => dirname(__DIR__),
12 | 'controllerNamespace' => 'backend\controllers',
13 | 'bootstrap' => ['log'],
14 | 'modules' => [],
15 | 'components' => [
16 | 'user' => [
17 | 'identityClass' => 'common\models\User',
18 | 'enableAutoLogin' => true,
19 | ],
20 | 'log' => [
21 | 'traceLevel' => YII_DEBUG ? 3 : 0,
22 | 'targets' => [
23 | [
24 | 'class' => 'yii\log\FileTarget',
25 | 'levels' => ['error', 'warning'],
26 | ],
27 | ],
28 | ],
29 | 'errorHandler' => [
30 | 'errorAction' => 'site/error',
31 | ],
32 | 'urlManager' => [
33 | 'enablePrettyUrl' => true,
34 | 'showScriptName' => false,
35 | ],
36 | 'resourceManager' => [
37 | 'class' => 'dosamigos\resourcemanager\FileSystemResourceManager',
38 | ],
39 | ],
40 | 'params' => $params,
41 | ];
42 |
--------------------------------------------------------------------------------
/backend/config/params.php:
--------------------------------------------------------------------------------
1 | 'admin@example.com',
4 | ];
5 |
--------------------------------------------------------------------------------
/backend/controllers/CategoryController.php:
--------------------------------------------------------------------------------
1 | [
21 | 'class' => VerbFilter::className(),
22 | 'actions' => [
23 | 'delete' => ['post'],
24 | ],
25 | ],
26 | ];
27 | }
28 |
29 | /**
30 | * Lists all Category models.
31 | * @return mixed
32 | */
33 | public function actionIndex()
34 | {
35 | $searchModel = new CategorySearch();
36 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
37 |
38 | return $this->render('index', [
39 | 'searchModel' => $searchModel,
40 | 'dataProvider' => $dataProvider,
41 | ]);
42 | }
43 |
44 | /**
45 | * Displays a single Category model.
46 | * @param integer $id
47 | * @return mixed
48 | */
49 | public function actionView($id)
50 | {
51 | return $this->render('view', [
52 | 'model' => $this->findModel($id),
53 | ]);
54 | }
55 |
56 | /**
57 | * Creates a new Category model.
58 | * If creation is successful, the browser will be redirected to the 'view' page.
59 | * @return mixed
60 | */
61 | public function actionCreate()
62 | {
63 | $model = new Category();
64 |
65 | if ($model->load(Yii::$app->request->post()) && $model->validate()) {
66 | if (!isset($model->parentId)) {
67 | $result = $model->saveNode();
68 | } else {
69 | $parent = Category::findOne($model->parentId);
70 | $result = $model->appendTo($parent);
71 | }
72 |
73 | if ($result) {
74 | return $this->redirect(['view', 'id' => $model->id]);
75 | }
76 | }
77 |
78 | return $this->render('create', [
79 | 'model' => $model,
80 | ]);
81 | }
82 |
83 | /**
84 | * Updates an existing Category model.
85 | * If update is successful, the browser will be redirected to the 'view' page.
86 | * @param integer $id
87 | * @return mixed
88 | */
89 | public function actionUpdate($id)
90 | {
91 | $model = $this->findModel($id);
92 |
93 | if ($model->load(Yii::$app->request->post()) && $model->validate()) {
94 | if (!isset($model->parentId)) {
95 | $result = $model->saveNode();
96 | } else {
97 | $parent = Category::findOne($model->parentId);
98 | $result = $model->appendTo($parent);
99 | }
100 |
101 | if ($result) {
102 | return $this->redirect(['view', 'id' => $model->id]);
103 | }
104 | }
105 |
106 | return $this->render('update', [
107 | 'model' => $model,
108 | ]);
109 | }
110 |
111 | /**
112 | * Deletes an existing Category model.
113 | * If deletion is successful, the browser will be redirected to the 'index' page.
114 | * @param integer $id
115 | * @return mixed
116 | */
117 | public function actionDelete($id)
118 | {
119 | $this->findModel($id)->delete();
120 |
121 | return $this->redirect(['index']);
122 | }
123 |
124 | /**
125 | * Finds the Category model based on its primary key value.
126 | * If the model is not found, a 404 HTTP exception will be thrown.
127 | * @param integer $id
128 | * @return Category the loaded model
129 | * @throws NotFoundHttpException if the model cannot be found
130 | */
131 | protected function findModel($id)
132 | {
133 | if (($model = Category::findOne($id)) !== null) {
134 | return $model;
135 | } else {
136 | throw new NotFoundHttpException('The requested page does not exist.');
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/backend/controllers/ProductController.php:
--------------------------------------------------------------------------------
1 | [
24 | 'class' => VerbFilter::className(),
25 | 'actions' => [
26 | 'delete' => ['post'],
27 | ],
28 | ],
29 | ];
30 | }
31 |
32 | /**
33 | * Lists all Product models.
34 | * @return mixed
35 | */
36 | public function actionIndex()
37 | {
38 | $searchModel = new ProductSearch();
39 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
40 |
41 | return $this->render('index', [
42 | 'searchModel' => $searchModel,
43 | 'dataProvider' => $dataProvider,
44 | ]);
45 | }
46 |
47 | /**
48 | * Displays a single Product model.
49 | * @param integer $id
50 | * @return mixed
51 | */
52 | public function actionView($id)
53 | {
54 | return $this->render('view', [
55 | 'model' => $this->findModel($id),
56 | ]);
57 | }
58 |
59 | /**
60 | * Creates a new Product model.
61 | * If creation is successful, the browser will be redirected to the 'view' page.
62 | * @return mixed
63 | */
64 | public function actionCreate()
65 | {
66 | $model = new Product();
67 |
68 | if ($model->load(Yii::$app->request->post())) {
69 | $model->file = UploadedFile::getInstance($model, 'file');
70 | if ($model->validate()) {
71 | $filename = 'uploads/' . md5($model->file->baseName) . '.' . $model->file->extension;
72 | if ($model->file->saveAs($filename)) {
73 | $model->image = Url::to($filename, true);
74 | $model->save(false);
75 | foreach ($model->categories as $categoryId) {
76 | $category = Category::findOne($categoryId);
77 | $model->link('categories', $category);
78 | }
79 | return $this->redirect(['view', 'id' => $model->id]);
80 | }
81 | }
82 | }
83 |
84 | return $this->render('create', [
85 | 'model' => $model,
86 | ]);
87 | }
88 |
89 | /**
90 | * Updates an existing Product model.
91 | * If update is successful, the browser will be redirected to the 'view' page.
92 | * @param integer $id
93 | * @return mixed
94 | */
95 | public function actionUpdate($id)
96 | {
97 | $model = $this->findModel($id);
98 |
99 | if ($model->load(Yii::$app->request->post())) {
100 | $model->file = UploadedFile::getInstance($model, 'file');
101 | if ($model->validate()) {
102 | $filename = 'uploads/' . md5($model->file->baseName) . '.' . $model->file->extension;
103 | if ($model->file->saveAs($filename)) {
104 | $model->image = Url::to($filename, true);
105 | $model->save(false);
106 | foreach ($model->categories as $categoryId) {
107 | $category = Category::findOne($categoryId);
108 | $model->link('categories', $category);
109 | }
110 | return $this->redirect(['view', 'id' => $model->id]);
111 | }
112 | }
113 | }
114 |
115 | return $this->render('update', [
116 | 'model' => $model,
117 | ]);
118 | }
119 |
120 | /**
121 | * Deletes an existing Product model.
122 | * If deletion is successful, the browser will be redirected to the 'index' page.
123 | * @param integer $id
124 | * @return mixed
125 | */
126 | public function actionDelete($id)
127 | {
128 | $this->findModel($id)->delete();
129 |
130 | return $this->redirect(['index']);
131 | }
132 |
133 | /**
134 | * Finds the Product model based on its primary key value.
135 | * If the model is not found, a 404 HTTP exception will be thrown.
136 | * @param integer $id
137 | * @return Product the loaded model
138 | * @throws NotFoundHttpException if the model cannot be found
139 | */
140 | protected function findModel($id)
141 | {
142 | if (($model = Product::findOne($id)) !== null) {
143 | return $model;
144 | } else {
145 | throw new NotFoundHttpException('The requested page does not exist.');
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/backend/controllers/SiteController.php:
--------------------------------------------------------------------------------
1 | [
22 | 'class' => AccessControl::className(),
23 | 'rules' => [
24 | [
25 | 'actions' => ['login', 'error'],
26 | 'allow' => true,
27 | ],
28 | [
29 | 'actions' => ['logout', 'index'],
30 | 'allow' => true,
31 | 'roles' => ['@'],
32 | ],
33 | ],
34 | ],
35 | 'verbs' => [
36 | 'class' => VerbFilter::className(),
37 | 'actions' => [
38 | 'logout' => ['post'],
39 | ],
40 | ],
41 | ];
42 | }
43 |
44 | /**
45 | * @inheritdoc
46 | */
47 | public function actions()
48 | {
49 | return [
50 | 'error' => [
51 | 'class' => 'yii\web\ErrorAction',
52 | ],
53 | ];
54 | }
55 |
56 | public function actionIndex()
57 | {
58 | return $this->render('index');
59 | }
60 |
61 | public function actionLogin()
62 | {
63 | if (!\Yii::$app->user->isGuest) {
64 | return $this->goHome();
65 | }
66 |
67 | $model = new LoginForm();
68 | if ($model->load(Yii::$app->request->post()) && $model->login()) {
69 | return $this->goBack();
70 | } else {
71 | return $this->render('login', [
72 | 'model' => $model,
73 | ]);
74 | }
75 | }
76 |
77 | public function actionLogout()
78 | {
79 | Yii::$app->user->logout();
80 |
81 | return $this->goHome();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/backend/models/.gitkeep:
--------------------------------------------------------------------------------
1 | *
2 |
--------------------------------------------------------------------------------
/backend/models/CategorySearch.php:
--------------------------------------------------------------------------------
1 | $query,
48 | ]);
49 |
50 | if (!($this->load($params) && $this->validate())) {
51 | return $dataProvider;
52 | }
53 |
54 | $query->andFilterWhere([
55 | 'id' => $this->id,
56 | ]);
57 |
58 | $query->andFilterWhere(['like', 'name', $this->name]);
59 |
60 | return $dataProvider;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/backend/models/ProductSearch.php:
--------------------------------------------------------------------------------
1 | $query,
49 | ]);
50 |
51 | if (!($this->load($params) && $this->validate())) {
52 | return $dataProvider;
53 | }
54 |
55 | $query->andFilterWhere([
56 | 'id' => $this->id,
57 | 'price' => $this->price,
58 | ]);
59 |
60 | $query->andFilterWhere(['like', 'name', $this->name])
61 | ->andFilterWhere(['like', 'short_description', $this->short_description])
62 | ->andFilterWhere(['like', 'image', $this->image]);
63 |
64 | return $dataProvider;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/backend/runtime/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/backend/views/category/_form.php:
--------------------------------------------------------------------------------
1 | dataFancytree();
12 | ?>
13 |
14 |
33 |
--------------------------------------------------------------------------------
/backend/views/category/_search.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | ['index'],
15 | 'method' => 'get',
16 | ]); ?>
17 |
18 | = $form->field($model, 'id') ?>
19 |
20 | = $form->field($model, 'name') ?>
21 |
22 |
23 | = Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
24 | = Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/backend/views/category/create.php:
--------------------------------------------------------------------------------
1 | title = 'Create Category';
10 | $this->params['breadcrumbs'][] = ['label' => 'Categories', 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 | = $this->render('_form', [
18 | 'model' => $model,
19 | ]) ?>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/backend/views/category/index.php:
--------------------------------------------------------------------------------
1 | title = 'Categories';
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 | render('_search', ['model' => $searchModel]); ?>
17 |
18 |
19 | = Html::a('Create Category', ['create'], ['class' => 'btn btn-success']) ?>
20 |
21 |
22 | = GridView::widget([
23 | 'dataProvider' => $dataProvider,
24 | 'filterModel' => $searchModel,
25 | 'columns' => [
26 | ['class' => 'yii\grid\SerialColumn'],
27 |
28 | 'id',
29 | 'name',
30 |
31 | ['class' => 'yii\grid\ActionColumn'],
32 | ],
33 | ]); ?>
34 |
35 |
36 |
--------------------------------------------------------------------------------
/backend/views/category/update.php:
--------------------------------------------------------------------------------
1 | title = 'Update Category: ' . ' ' . $model->name;
9 | $this->params['breadcrumbs'][] = ['label' => 'Categories', 'url' => ['index']];
10 | $this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];
11 | $this->params['breadcrumbs'][] = 'Update';
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 | = $this->render('_form', [
18 | 'model' => $model,
19 | ]) ?>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/backend/views/category/view.php:
--------------------------------------------------------------------------------
1 | title = $model->name;
10 | $this->params['breadcrumbs'][] = ['label' => 'Categories', 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 |
18 | = Html::a('Create', ['create'], ['class' => 'btn btn-success']) ?>
19 | = Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
20 | = Html::a('Delete', ['delete', 'id' => $model->id], [
21 | 'class' => 'btn btn-danger',
22 | 'data' => [
23 | 'confirm' => 'Are you sure you want to delete this item?',
24 | 'method' => 'post',
25 | ],
26 | ]) ?>
27 |
28 |
29 | = DetailView::widget([
30 | 'model' => $model,
31 | 'attributes' => [
32 | 'id',
33 | 'name',
34 | ],
35 | ]) ?>
36 |
37 |
38 |
--------------------------------------------------------------------------------
/backend/views/layouts/main.php:
--------------------------------------------------------------------------------
1 |
13 | beginPage() ?>
14 |
15 |
16 |
17 |
18 |
19 | = Html::csrfMetaTags() ?>
20 | = Html::encode($this->title) ?>
21 | head() ?>
22 |
23 |
24 | beginBody() ?>
25 |
26 | 'My Company',
29 | 'brandUrl' => Yii::$app->homeUrl,
30 | 'options' => [
31 | 'class' => 'navbar-inverse navbar-fixed-top',
32 | ],
33 | ]);
34 | $menuItems = [
35 | ['label' => 'Home', 'url' => ['/site/index']],
36 | ['label' => 'Products', 'url' => ['/product/index']],
37 | ['label' => 'Categories', 'url' => ['/category/index']],
38 | ];
39 | if (Yii::$app->user->isGuest) {
40 | $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']];
41 | } else {
42 | $menuItems[] = [
43 | 'label' => 'Logout (' . Yii::$app->user->identity->username . ')',
44 | 'url' => ['/site/logout'],
45 | 'linkOptions' => ['data-method' => 'post']
46 | ];
47 | }
48 | echo Nav::widget([
49 | 'options' => ['class' => 'navbar-nav navbar-right'],
50 | 'items' => $menuItems,
51 | ]);
52 | NavBar::end();
53 | ?>
54 |
55 |
56 | = Breadcrumbs::widget([
57 | 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
58 | ]) ?>
59 | = $content ?>
60 |
61 |
62 |
63 |
69 |
70 | endBody() ?>
71 |
72 |
73 | endPage() ?>
74 |
--------------------------------------------------------------------------------
/backend/views/product/_form.php:
--------------------------------------------------------------------------------
1 |
12 |
13 |
42 |
--------------------------------------------------------------------------------
/backend/views/product/_search.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | ['index'],
15 | 'method' => 'get',
16 | ]); ?>
17 |
18 | = $form->field($model, 'id') ?>
19 |
20 | = $form->field($model, 'name') ?>
21 |
22 | = $form->field($model, 'price') ?>
23 |
24 | = $form->field($model, 'short_description') ?>
25 |
26 | = $form->field($model, 'image') ?>
27 |
28 | field($model, 'quantity') ?>
29 |
30 |
31 | = Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
32 | = Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/backend/views/product/create.php:
--------------------------------------------------------------------------------
1 | title = 'Create Product';
10 | $this->params['breadcrumbs'][] = ['label' => 'Products', 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 | = $this->render('_form', [
18 | 'model' => $model,
19 | ]) ?>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/backend/views/product/index.php:
--------------------------------------------------------------------------------
1 | title = 'Products';
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 | render('_search', ['model' => $searchModel]); ?>
17 |
18 |
19 | = Html::a('Create Product', ['create'], ['class' => 'btn btn-success']) ?>
20 |
21 |
22 | = GridView::widget([
23 | 'dataProvider' => $dataProvider,
24 | 'filterModel' => $searchModel,
25 | 'columns' => [
26 | ['class' => 'yii\grid\SerialColumn'],
27 |
28 | 'id',
29 | 'name',
30 | 'price',
31 | 'short_description:ntext',
32 | 'image',
33 | // 'quantity',
34 |
35 | ['class' => 'yii\grid\ActionColumn'],
36 | ],
37 | ]); ?>
38 |
39 |
40 |
--------------------------------------------------------------------------------
/backend/views/product/update.php:
--------------------------------------------------------------------------------
1 | title = 'Update Product: ' . ' ' . $model->name;
9 | $this->params['breadcrumbs'][] = ['label' => 'Products', 'url' => ['index']];
10 | $this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];
11 | $this->params['breadcrumbs'][] = 'Update';
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 | = $this->render('_form', [
18 | 'model' => $model,
19 | ]) ?>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/backend/views/product/view.php:
--------------------------------------------------------------------------------
1 | title = $model->name;
10 | $this->params['breadcrumbs'][] = ['label' => 'Products', 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 |
18 | = Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
19 | = Html::a('Delete', ['delete', 'id' => $model->id], [
20 | 'class' => 'btn btn-danger',
21 | 'data' => [
22 | 'confirm' => 'Are you sure you want to delete this item?',
23 | 'method' => 'post',
24 | ],
25 | ]) ?>
26 |
27 |
28 | = DetailView::widget([
29 | 'model' => $model,
30 | 'attributes' => [
31 | 'id',
32 | 'name',
33 | 'price',
34 | 'short_description:ntext',
35 | 'image',
36 | ],
37 | ]) ?>
38 |
39 |
40 |
--------------------------------------------------------------------------------
/backend/views/site/error.php:
--------------------------------------------------------------------------------
1 | title = $name;
11 | ?>
12 |
13 |
14 |
= Html::encode($this->title) ?>
15 |
16 |
17 | = nl2br(Html::encode($message)) ?>
18 |
19 |
20 |
21 | The above error occurred while the Web server was processing your request.
22 |
23 |
24 | Please contact us if you think this is a server error. Thank you.
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/backend/views/site/index.php:
--------------------------------------------------------------------------------
1 | title = 'My Yii Application';
5 | ?>
6 |
7 |
8 |
9 |
Congratulations!
10 |
11 |
You have successfully created your Yii-powered application.
12 |
13 |
Get started with Yii
14 |
15 |
16 |
17 |
18 |
19 |
20 |
Heading
21 |
22 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
23 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
24 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
25 | fugiat nulla pariatur.
26 |
27 |
Yii Documentation »
28 |
29 |
30 |
Heading
31 |
32 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
33 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
34 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
35 | fugiat nulla pariatur.
36 |
37 |
Yii Forum »
38 |
39 |
40 |
Heading
41 |
42 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
43 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
44 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
45 | fugiat nulla pariatur.
46 |
47 |
Yii Extensions »
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/backend/views/site/login.php:
--------------------------------------------------------------------------------
1 | title = 'Login';
10 | $this->params['breadcrumbs'][] = $this->title;
11 | ?>
12 |
13 |
= Html::encode($this->title) ?>
14 |
15 |
Please fill out the following fields to login:
16 |
17 |
18 |
19 | 'login-form']); ?>
20 | = $form->field($model, 'username') ?>
21 | = $form->field($model, 'password')->passwordInput() ?>
22 | = $form->field($model, 'rememberMe')->checkbox() ?>
23 |
24 | = Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/backend/web/.gitignore:
--------------------------------------------------------------------------------
1 | /index.php
2 | /index-test.php
3 | /uploads
4 |
--------------------------------------------------------------------------------
/backend/web/.htaccess:
--------------------------------------------------------------------------------
1 | RewriteEngine on
2 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
3 | RewriteCond %{REQUEST_FILENAME} !-f
4 | RewriteCond %{REQUEST_FILENAME} !-d
5 | RewriteRule . index.php
--------------------------------------------------------------------------------
/backend/web/assets/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/backend/web/css/site.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | }
5 |
6 | .wrap {
7 | min-height: 100%;
8 | height: auto;
9 | margin: 0 auto -60px;
10 | padding: 0 0 60px;
11 | }
12 |
13 | .wrap > .container {
14 | padding: 70px 15px 20px;
15 | }
16 |
17 | .footer {
18 | height: 60px;
19 | background-color: #f5f5f5;
20 | border-top: 1px solid #ddd;
21 | padding-top: 20px;
22 | }
23 |
24 | .jumbotron {
25 | text-align: center;
26 | background-color: transparent;
27 | }
28 |
29 | .jumbotron .btn {
30 | font-size: 21px;
31 | padding: 14px 24px;
32 | }
33 |
34 | .not-set {
35 | color: #c55;
36 | font-style: italic;
37 | }
38 |
39 | /* add sorting icons to gridview sort links */
40 | a.asc:after, a.desc:after {
41 | position: relative;
42 | top: 1px;
43 | display: inline-block;
44 | font-family: 'Glyphicons Halflings';
45 | font-style: normal;
46 | font-weight: normal;
47 | line-height: 1;
48 | padding-left: 5px;
49 | }
50 |
51 | a.asc:after {
52 | content: /*"\e113"*/ "\e151";
53 | }
54 |
55 | a.desc:after {
56 | content: /*"\e114"*/ "\e152";
57 | }
58 |
59 | .sort-numerical a.asc:after {
60 | content: "\e153";
61 | }
62 |
63 | .sort-numerical a.desc:after {
64 | content: "\e154";
65 | }
66 |
67 | .sort-ordinal a.asc:after {
68 | content: "\e155";
69 | }
70 |
71 | .sort-ordinal a.desc:after {
72 | content: "\e156";
73 | }
74 |
75 | .grid-view th {
76 | white-space: nowrap;
77 | }
78 |
79 | .hint-block {
80 | display: block;
81 | margin-top: 5px;
82 | color: #999;
83 | }
84 |
85 | .error-summary {
86 | color: #a94442;
87 | background: #fdf7f7;
88 | border-left: 3px solid #eed3d7;
89 | padding: 10px 20px;
90 | margin: 0 0 15px 0;
91 | }
92 |
93 | ul.fancytree-container {
94 | line-height: 1.42857143;
95 | color: #555;
96 | background-color: #fff;
97 | border: 1px solid #ccc;
98 | border-radius: 4px;
99 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
100 | transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
101 | }
102 |
103 | span.fancytree-focused span.fancytree-title {
104 | outline: none;
105 | }
--------------------------------------------------------------------------------
/backend/web/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NullRefExcep/yii2-shopper/176e51c5e1a224511119876b11e2e746366a388f/backend/web/favicon.ico
--------------------------------------------------------------------------------
/backend/web/robots.txt:
--------------------------------------------------------------------------------
1 | User-Agent: *
2 | Disallow: /
3 |
--------------------------------------------------------------------------------
/common/components/Catalog.php:
--------------------------------------------------------------------------------
1 | dataFancytree();
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/common/config/.gitignore:
--------------------------------------------------------------------------------
1 | main-local.php
2 | params-local.php
3 |
--------------------------------------------------------------------------------
/common/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | dirname(dirname(__DIR__)) . '/vendor',
4 | 'components' => [
5 | 'cache' => [
6 | 'class' => 'yii\caching\FileCache',
7 | ],
8 | ],
9 | ];
10 |
--------------------------------------------------------------------------------
/common/config/params.php:
--------------------------------------------------------------------------------
1 | 'admin@example.com',
4 | 'supportEmail' => 'support@example.com',
5 | 'user.passwordResetTokenExpire' => 3600,
6 | ];
7 |
--------------------------------------------------------------------------------
/common/mail/layouts/html.php:
--------------------------------------------------------------------------------
1 |
8 | beginPage() ?>
9 |
10 |
11 |
12 |
13 | = Html::encode($this->title) ?>
14 | head() ?>
15 |
16 |
17 | beginBody() ?>
18 | = $content ?>
19 | endBody() ?>
20 |
21 |
22 | endPage() ?>
23 |
--------------------------------------------------------------------------------
/common/mail/passwordResetToken.php:
--------------------------------------------------------------------------------
1 | urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]);
8 | ?>
9 |
10 | Hello = Html::encode($user->username) ?>,
11 |
12 | Follow the link below to reset your password:
13 |
14 | = Html::a(Html::encode($resetLink), $resetLink) ?>
15 |
--------------------------------------------------------------------------------
/common/models/Category.php:
--------------------------------------------------------------------------------
1 | 255],
43 | [
44 | ['parentId'],
45 | 'compare',
46 | 'compareAttribute' => 'id',
47 | 'operator' => '!=',
48 | 'when' => function () {
49 | return !$this->isNewRecord;
50 | }
51 | ],
52 | [['parentId'], 'safe']
53 | ];
54 | }
55 |
56 | /**
57 | * @inheritdoc
58 | */
59 | public function attributeLabels()
60 | {
61 | return [
62 | 'id' => 'ID',
63 | 'name' => 'Name',
64 | ];
65 | }
66 |
67 | public function behaviors()
68 | {
69 | return [
70 | 'nested' => [
71 | 'class' => NestedSetBehavior::className(),
72 | 'hasManyRoots' => true,
73 | 'titleAttribute' => 'name',
74 | 'idAttribute' => 'id',
75 | 'rootAttribute' => 'root',
76 | 'leftAttribute' => 'left',
77 | 'rightAttribute' => 'right',
78 | 'levelAttribute' => 'level',
79 | ],
80 | ];
81 | }
82 |
83 | public static function find()
84 | {
85 | return new NestedSetQuery(get_called_class());
86 | }
87 |
88 |
89 | public function getProducts()
90 | {
91 | return $this->hasMany(Product::className(), ['id' => 'product_id'])
92 | ->viaTable('category_product', ['category_id' => 'id']);
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/common/models/LoginForm.php:
--------------------------------------------------------------------------------
1 | hasErrors()) {
43 | $user = $this->getUser();
44 | if (!$user || !$user->validatePassword($this->password)) {
45 | $this->addError($attribute, 'Incorrect username or password.');
46 | }
47 | }
48 | }
49 |
50 | /**
51 | * Logs in a user using the provided username and password.
52 | *
53 | * @return boolean whether the user is logged in successfully
54 | */
55 | public function login()
56 | {
57 | if ($this->validate()) {
58 | return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
59 | } else {
60 | return false;
61 | }
62 | }
63 |
64 | /**
65 | * Finds user by [[username]]
66 | *
67 | * @return User|null
68 | */
69 | public function getUser()
70 | {
71 | if ($this->_user === false) {
72 | $this->_user = User::findByUsername($this->username);
73 | }
74 |
75 | return $this->_user;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/common/models/Product.php:
--------------------------------------------------------------------------------
1 | 255],
41 | [['file'], 'file', 'extensions' => ['jpg', 'png']],
42 | [['categories'], 'safe'],
43 | ];
44 | }
45 |
46 | /**
47 | * @inheritdoc
48 | */
49 | public function attributeLabels()
50 | {
51 | return [
52 | 'id' => 'ID',
53 | 'name' => 'Name',
54 | 'price' => 'Price',
55 | 'description' => 'Description',
56 | 'image' => 'Image',
57 | ];
58 | }
59 |
60 | public function getImage()
61 | {
62 | return $this->image;
63 | }
64 |
65 | public function getCategories()
66 | {
67 | return $this->hasMany(Category::className(), ['id' => 'category_id'])
68 | ->viaTable('category_product', ['product_id' => 'id']);
69 | }
70 |
71 | /**
72 | * @return string
73 | */
74 | public function getId()
75 | {
76 | return $this->id;
77 | }
78 |
79 | /**
80 | * @return integer
81 | */
82 | public function getPrice()
83 | {
84 | return $this->price;
85 | }
86 |
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/common/models/User.php:
--------------------------------------------------------------------------------
1 | self::STATUS_ACTIVE],
56 | ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
57 |
58 | ['role', 'default', 'value' => self::ROLE_USER],
59 | ['role', 'in', 'range' => [self::ROLE_USER]],
60 | ];
61 | }
62 |
63 | /**
64 | * @inheritdoc
65 | */
66 | public static function findIdentity($id)
67 | {
68 | return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
69 | }
70 |
71 | /**
72 | * @inheritdoc
73 | */
74 | public static function findIdentityByAccessToken($token, $type = null)
75 | {
76 | throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
77 | }
78 |
79 | /**
80 | * Finds user by username
81 | *
82 | * @param string $username
83 | * @return static|null
84 | */
85 | public static function findByUsername($username)
86 | {
87 | return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
88 | }
89 |
90 | /**
91 | * Finds user by password reset token
92 | *
93 | * @param string $token password reset token
94 | * @return static|null
95 | */
96 | public static function findByPasswordResetToken($token)
97 | {
98 | if (!static::isPasswordResetTokenValid($token)) {
99 | return null;
100 | }
101 |
102 | return static::findOne([
103 | 'password_reset_token' => $token,
104 | 'status' => self::STATUS_ACTIVE,
105 | ]);
106 | }
107 |
108 | /**
109 | * Finds out if password reset token is valid
110 | *
111 | * @param string $token password reset token
112 | * @return boolean
113 | */
114 | public static function isPasswordResetTokenValid($token)
115 | {
116 | if (empty($token)) {
117 | return false;
118 | }
119 | $expire = Yii::$app->params['user.passwordResetTokenExpire'];
120 | $parts = explode('_', $token);
121 | $timestamp = (int) end($parts);
122 | return $timestamp + $expire >= time();
123 | }
124 |
125 | /**
126 | * @inheritdoc
127 | */
128 | public function getId()
129 | {
130 | return $this->getPrimaryKey();
131 | }
132 |
133 | /**
134 | * @inheritdoc
135 | */
136 | public function getAuthKey()
137 | {
138 | return $this->auth_key;
139 | }
140 |
141 | /**
142 | * @inheritdoc
143 | */
144 | public function validateAuthKey($authKey)
145 | {
146 | return $this->getAuthKey() === $authKey;
147 | }
148 |
149 | /**
150 | * Validates password
151 | *
152 | * @param string $password password to validate
153 | * @return boolean if password provided is valid for current user
154 | */
155 | public function validatePassword($password)
156 | {
157 | return Yii::$app->security->validatePassword($password, $this->password_hash);
158 | }
159 |
160 | /**
161 | * Generates password hash from password and sets it to the model
162 | *
163 | * @param string $password
164 | */
165 | public function setPassword($password)
166 | {
167 | $this->password_hash = Yii::$app->security->generatePasswordHash($password);
168 | }
169 |
170 | /**
171 | * Generates "remember me" authentication key
172 | */
173 | public function generateAuthKey()
174 | {
175 | $this->auth_key = Yii::$app->security->generateRandomString();
176 | }
177 |
178 | /**
179 | * Generates new password reset token
180 | */
181 | public function generatePasswordResetToken()
182 | {
183 | $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
184 | }
185 |
186 | /**
187 | * Removes password reset token
188 | */
189 | public function removePasswordResetToken()
190 | {
191 | $this->password_reset_token = null;
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "null-ref-excep/yii2-shopper",
3 | "description": "E-commerce application template based on Yii 2 Advanced Application Template",
4 | "keywords": [
5 | "yii2",
6 | "framework",
7 | "application template",
8 | "shop",
9 | "e-commerce"
10 | ],
11 | "type": "project",
12 | "license": "MIT",
13 | "support": {
14 | "issues": "https://github.com/NullRefExcep/yii2-shopper/issues",
15 | "wiki": "https://github.com/NullRefExcep/yii2-shopper/wiki",
16 | "source": "https://github.com/NullRefExcep/yii2-shopper"
17 | },
18 | "minimum-stability": "dev",
19 | "require": {
20 | "php": ">=5.4.0",
21 | "yiisoft/yii2": "2.0.0",
22 | "yiisoft/yii2-bootstrap": "2.0.0",
23 | "yiisoft/yii2-swiftmailer": "2.0.0",
24 | "rmrevin/yii2-fontawesome": "2.5.0",
25 | "kartik-v/yii2-widgets": "*",
26 | "wbraganca/yii2-nested-set-behavior": "*",
27 | "wbraganca/yii2-fancytree-widget": "*",
28 | "omnilight/yii2-shopping-cart": "*"
29 | },
30 | "require-dev": {
31 | "yiisoft/yii2-codeception": "2.0.0",
32 | "yiisoft/yii2-debug": "2.0.0",
33 | "yiisoft/yii2-gii": "2.0.0",
34 | "yiisoft/yii2-faker": "2.0.0"
35 | },
36 | "config": {
37 | "process-timeout": 1800
38 | },
39 | "extra": {
40 | "asset-installer-paths": {
41 | "npm-asset-library": "vendor/npm",
42 | "bower-asset-library": "vendor/bower"
43 | }
44 | },
45 | "repositories": [
46 | {
47 | "type": "vcs",
48 | "url": "https://github.com/serhiyvinichuk/yii2-fancytree-widget"
49 | }
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/console/config/.gitignore:
--------------------------------------------------------------------------------
1 | main-local.php
2 | params-local.php
--------------------------------------------------------------------------------
/console/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | 'app-console',
11 | 'basePath' => dirname(__DIR__),
12 | 'bootstrap' => ['log', 'gii'],
13 | 'controllerNamespace' => 'console\controllers',
14 | 'modules' => [
15 | 'gii' => 'yii\gii\Module',
16 | ],
17 | 'components' => [
18 | 'log' => [
19 | 'targets' => [
20 | [
21 | 'class' => 'yii\log\FileTarget',
22 | 'levels' => ['error', 'warning'],
23 | ],
24 | ],
25 | ],
26 | ],
27 | 'params' => $params,
28 | ];
29 |
--------------------------------------------------------------------------------
/console/config/params.php:
--------------------------------------------------------------------------------
1 | 'admin@example.com',
4 | ];
5 |
--------------------------------------------------------------------------------
/console/controllers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NullRefExcep/yii2-shopper/176e51c5e1a224511119876b11e2e746366a388f/console/controllers/.gitkeep
--------------------------------------------------------------------------------
/console/migrations/m130524_201442_init.php:
--------------------------------------------------------------------------------
1 | db->driverName === 'mysql') {
12 | // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
13 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
14 | }
15 |
16 | $this->createTable('{{%user}}', [
17 | 'id' => Schema::TYPE_PK,
18 | 'username' => Schema::TYPE_STRING . ' NOT NULL',
19 | 'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL',
20 | 'password_hash' => Schema::TYPE_STRING . ' NOT NULL',
21 | 'password_reset_token' => Schema::TYPE_STRING,
22 | 'email' => Schema::TYPE_STRING . ' NOT NULL',
23 | 'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
24 |
25 | 'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
26 | 'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
27 | 'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
28 | ], $tableOptions);
29 | }
30 |
31 | public function down()
32 | {
33 | $this->dropTable('{{%user}}');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/console/migrations/m141109_104615_create_products.php:
--------------------------------------------------------------------------------
1 | createTable('{{%product}}', [
11 | 'id' => Schema::TYPE_PK,
12 | 'name' => Schema::TYPE_STRING,
13 | 'price' => Schema::TYPE_FLOAT,
14 | 'short_description' => Schema::TYPE_TEXT,
15 | 'long_description' => Schema::TYPE_TEXT,
16 | 'image' => Schema::TYPE_STRING,
17 | ]);
18 | }
19 |
20 | public function down()
21 | {
22 | $this->dropTable('{{%product}}');
23 | return true;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/console/migrations/m141109_111923_create_categories.php:
--------------------------------------------------------------------------------
1 | createTable('{{%category}}', [
11 | 'id' => Schema::TYPE_PK,
12 | 'name' => Schema::TYPE_STRING,
13 | 'root' => Schema::TYPE_INTEGER . ' UNSIGNED DEFAULT NULL',
14 | 'left' => Schema::TYPE_INTEGER . ' UNSIGNED NOT NULL',
15 | 'right' => Schema::TYPE_INTEGER . ' UNSIGNED NOT NULL',
16 | 'level' => Schema::TYPE_SMALLINT . ' UNSIGNED NOT NULL',
17 | ]);
18 | $this->createIndex('root', '{{%category}}', ['root']);
19 | $this->createIndex('left', '{{%category}}', ['left']);
20 | $this->createIndex('right', '{{%category}}', ['right']);
21 | $this->createIndex('level', '{{%category}}', ['level']);
22 | }
23 |
24 | public function down()
25 | {
26 | $this->dropTable('{{%category}}');
27 | return true;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/console/migrations/m141113_155131_create_category_product.php:
--------------------------------------------------------------------------------
1 | createTable('{{%category_product}}', [
11 | 'category_id' => Schema::TYPE_INTEGER,
12 | 'product_id' => Schema::TYPE_INTEGER,
13 | ]);
14 | $this->addPrimaryKey('pk', '{{%category_product}}', ['category_id', 'product_id']);
15 | }
16 |
17 | public function down()
18 | {
19 | $this->dropTable('{{%category_product}}');
20 | return true;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/console/models/.gitkeep:
--------------------------------------------------------------------------------
1 | *
2 |
--------------------------------------------------------------------------------
/console/runtime/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/environments/dev/backend/config/main-local.php:
--------------------------------------------------------------------------------
1 | [
5 | 'request' => [
6 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
7 | 'cookieValidationKey' => '',
8 | ],
9 | ],
10 | ];
11 |
12 | if (!YII_ENV_TEST) {
13 | // configuration adjustments for 'dev' environment
14 | $config['bootstrap'][] = 'debug';
15 | $config['modules']['debug'] = 'yii\debug\Module';
16 |
17 | $config['bootstrap'][] = 'gii';
18 | $config['modules']['gii'] = 'yii\gii\Module';
19 | }
20 |
21 | return $config;
22 |
--------------------------------------------------------------------------------
/environments/dev/backend/config/params-local.php:
--------------------------------------------------------------------------------
1 | run();
20 |
--------------------------------------------------------------------------------
/environments/dev/backend/web/index.php:
--------------------------------------------------------------------------------
1 | run();
19 |
--------------------------------------------------------------------------------
/environments/dev/common/config/main-local.php:
--------------------------------------------------------------------------------
1 | [
4 | 'db' => [
5 | 'class' => 'yii\db\Connection',
6 | 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
7 | 'username' => 'root',
8 | 'password' => '',
9 | 'charset' => 'utf8',
10 | ],
11 | 'mailer' => [
12 | 'class' => 'yii\swiftmailer\Mailer',
13 | 'viewPath' => '@common/mail',
14 | // send all mails to a file by default. You have to set
15 | // 'useFileTransport' to false and configure a transport
16 | // for the mailer to send real emails.
17 | 'useFileTransport' => true,
18 | ],
19 | ],
20 | ];
21 |
--------------------------------------------------------------------------------
/environments/dev/common/config/params-local.php:
--------------------------------------------------------------------------------
1 | [
5 | 'request' => [
6 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
7 | 'cookieValidationKey' => '',
8 | ],
9 | ],
10 | ];
11 |
12 | if (!YII_ENV_TEST) {
13 | // configuration adjustments for 'dev' environment
14 | $config['bootstrap'][] = 'debug';
15 | $config['modules']['debug'] = 'yii\debug\Module';
16 |
17 | $config['bootstrap'][] = 'gii';
18 | $config['modules']['gii'] = 'yii\gii\Module';
19 | }
20 |
21 | return $config;
22 |
--------------------------------------------------------------------------------
/environments/dev/frontend/config/params-local.php:
--------------------------------------------------------------------------------
1 | run();
19 |
--------------------------------------------------------------------------------
/environments/dev/frontend/web/index.php:
--------------------------------------------------------------------------------
1 | run();
19 |
--------------------------------------------------------------------------------
/environments/dev/yii:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | run();
32 | exit($exitCode);
33 |
--------------------------------------------------------------------------------
/environments/index.php:
--------------------------------------------------------------------------------
1 | [
11 | * 'path' => 'directory storing the local files',
12 | * 'setWritable' => [
13 | * // list of directories that should be set writable
14 | * ],
15 | * 'setExecutable' => [
16 | * // list of directories that should be set executable
17 | * ],
18 | * 'setCookieValidationKey' => [
19 | * // list of config files that need to be inserted with automatically generated cookie validation keys
20 | * ],
21 | * 'createSymlink' => [
22 | * // list of symlinks to be created. Keys are symlinks, and values are the targets.
23 | * ],
24 | * ],
25 | * ];
26 | * ```
27 | */
28 | return [
29 | 'Development' => [
30 | 'path' => 'dev',
31 | 'setWritable' => [
32 | 'backend/runtime',
33 | 'backend/web/assets',
34 | 'frontend/runtime',
35 | 'frontend/web/assets',
36 | ],
37 | 'setExecutable' => [
38 | 'yii',
39 | ],
40 | 'setCookieValidationKey' => [
41 | 'backend/config/main-local.php',
42 | 'frontend/config/main-local.php',
43 | ],
44 | ],
45 | 'Production' => [
46 | 'path' => 'prod',
47 | 'setWritable' => [
48 | 'backend/runtime',
49 | 'backend/web/assets',
50 | 'frontend/runtime',
51 | 'frontend/web/assets',
52 | ],
53 | 'setExecutable' => [
54 | 'yii',
55 | ],
56 | 'setCookieValidationKey' => [
57 | 'backend/config/main-local.php',
58 | 'frontend/config/main-local.php',
59 | ],
60 | ],
61 | ];
62 |
--------------------------------------------------------------------------------
/environments/prod/backend/config/main-local.php:
--------------------------------------------------------------------------------
1 | [
4 | 'request' => [
5 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
6 | 'cookieValidationKey' => '',
7 | ],
8 | ],
9 | ];
10 |
--------------------------------------------------------------------------------
/environments/prod/backend/config/params-local.php:
--------------------------------------------------------------------------------
1 | run();
19 |
--------------------------------------------------------------------------------
/environments/prod/common/config/main-local.php:
--------------------------------------------------------------------------------
1 | [
4 | 'db' => [
5 | 'class' => 'yii\db\Connection',
6 | 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
7 | 'username' => 'root',
8 | 'password' => '',
9 | 'charset' => 'utf8',
10 | ],
11 | 'mailer' => [
12 | 'class' => 'yii\swiftmailer\Mailer',
13 | 'viewPath' => '@common/mail',
14 | ],
15 | ],
16 | ];
17 |
--------------------------------------------------------------------------------
/environments/prod/common/config/params-local.php:
--------------------------------------------------------------------------------
1 | [
4 | 'request' => [
5 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
6 | 'cookieValidationKey' => '',
7 | ],
8 | ],
9 | ];
10 |
--------------------------------------------------------------------------------
/environments/prod/frontend/config/params-local.php:
--------------------------------------------------------------------------------
1 | run();
19 |
--------------------------------------------------------------------------------
/environments/prod/yii:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | run();
32 | exit($exitCode);
33 |
--------------------------------------------------------------------------------
/frontend/assets/AppAsset.php:
--------------------------------------------------------------------------------
1 |
14 | * @since 2.0
15 | */
16 | class AppAsset extends AssetBundle
17 | {
18 | public $basePath = '@webroot';
19 | public $baseUrl = '@web';
20 | public $css = [
21 | 'css/site.css',
22 | ];
23 | public $js = [
24 | ];
25 | public $depends = [
26 | 'yii\web\YiiAsset',
27 | 'yii\bootstrap\BootstrapAsset',
28 | ];
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/config/.gitignore:
--------------------------------------------------------------------------------
1 | main-local.php
2 | params-local.php
--------------------------------------------------------------------------------
/frontend/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | 'app-frontend',
11 | 'basePath' => dirname(__DIR__),
12 | 'bootstrap' => ['log'],
13 | 'controllerNamespace' => 'frontend\controllers',
14 | 'components' => [
15 | 'user' => [
16 | 'identityClass' => 'common\models\User',
17 | 'enableAutoLogin' => true,
18 | ],
19 | 'log' => [
20 | 'traceLevel' => YII_DEBUG ? 3 : 0,
21 | 'targets' => [
22 | [
23 | 'class' => 'yii\log\FileTarget',
24 | 'levels' => ['error', 'warning'],
25 | ],
26 | ],
27 | ],
28 | 'errorHandler' => [
29 | 'errorAction' => 'site/error',
30 | ],
31 | 'urlManager' => [
32 | 'enablePrettyUrl' => true,
33 | 'showScriptName' => false,
34 | ],
35 | 'catalog' => [
36 | 'class' => 'common\components\Catalog',
37 | ]
38 | ],
39 | 'params' => $params,
40 | ];
41 |
--------------------------------------------------------------------------------
/frontend/config/params.php:
--------------------------------------------------------------------------------
1 | 'admin@example.com',
4 | ];
5 |
--------------------------------------------------------------------------------
/frontend/controllers/CategoryController.php:
--------------------------------------------------------------------------------
1 | render('index');
13 | }
14 |
15 | public function actionView($id)
16 | {
17 | $dataProvider = new ActiveDataProvider(['query' => Product::find()]);
18 |
19 | return $this->render('view', ['dataProvider' => $dataProvider]);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/controllers/SiteController.php:
--------------------------------------------------------------------------------
1 | [
31 | 'class' => AccessControl::className(),
32 | 'only' => ['logout', 'signup'],
33 | 'rules' => [
34 | [
35 | 'actions' => ['signup'],
36 | 'allow' => true,
37 | 'roles' => ['?'],
38 | ],
39 | [
40 | 'actions' => ['logout'],
41 | 'allow' => true,
42 | 'roles' => ['@'],
43 | ],
44 | ],
45 | ],
46 | 'verbs' => [
47 | 'class' => VerbFilter::className(),
48 | 'actions' => [
49 | 'logout' => ['post'],
50 | ],
51 | ],
52 | ];
53 | }
54 |
55 | /**
56 | * @inheritdoc
57 | */
58 | public function actions()
59 | {
60 | return [
61 | 'error' => [
62 | 'class' => 'yii\web\ErrorAction',
63 | ],
64 | 'captcha' => [
65 | 'class' => 'yii\captcha\CaptchaAction',
66 | 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
67 | ],
68 | ];
69 | }
70 |
71 | public function actionIndex()
72 | {
73 | $dataProvider = new ActiveDataProvider(['query' => Product::find()]);
74 | return $this->render('index', ['dataProvider' => $dataProvider]);
75 | }
76 |
77 | public function actionLogin()
78 | {
79 | if (!\Yii::$app->user->isGuest) {
80 | return $this->goHome();
81 | }
82 |
83 | $model = new LoginForm();
84 | if ($model->load(Yii::$app->request->post()) && $model->login()) {
85 | return $this->goBack();
86 | } else {
87 | return $this->render('login', [
88 | 'model' => $model,
89 | ]);
90 | }
91 | }
92 |
93 | public function actionLogout()
94 | {
95 | Yii::$app->user->logout();
96 |
97 | return $this->goHome();
98 | }
99 |
100 | public function actionContact()
101 | {
102 | $model = new ContactForm();
103 | if ($model->load(Yii::$app->request->post()) && $model->validate()) {
104 | if ($model->sendEmail(Yii::$app->params['adminEmail'])) {
105 | Yii::$app->session->setFlash('success', 'Thank you for contacting us. We will respond to you as soon as possible.');
106 | } else {
107 | Yii::$app->session->setFlash('error', 'There was an error sending email.');
108 | }
109 |
110 | return $this->refresh();
111 | } else {
112 | return $this->render('contact', [
113 | 'model' => $model,
114 | ]);
115 | }
116 | }
117 |
118 | public function actionAbout()
119 | {
120 | return $this->render('about');
121 | }
122 |
123 | public function actionSignup()
124 | {
125 | $model = new SignupForm();
126 | if ($model->load(Yii::$app->request->post())) {
127 | if ($user = $model->signup()) {
128 | if (Yii::$app->getUser()->login($user)) {
129 | return $this->goHome();
130 | }
131 | }
132 | }
133 |
134 | return $this->render('signup', [
135 | 'model' => $model,
136 | ]);
137 | }
138 |
139 | public function actionRequestPasswordReset()
140 | {
141 | $model = new PasswordResetRequestForm();
142 | if ($model->load(Yii::$app->request->post()) && $model->validate()) {
143 | if ($model->sendEmail()) {
144 | Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.');
145 |
146 | return $this->goHome();
147 | } else {
148 | Yii::$app->getSession()->setFlash('error', 'Sorry, we are unable to reset password for email provided.');
149 | }
150 | }
151 |
152 | return $this->render('requestPasswordResetToken', [
153 | 'model' => $model,
154 | ]);
155 | }
156 |
157 | public function actionResetPassword($token)
158 | {
159 | try {
160 | $model = new ResetPasswordForm($token);
161 | } catch (InvalidParamException $e) {
162 | throw new BadRequestHttpException($e->getMessage());
163 | }
164 |
165 | if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) {
166 | Yii::$app->getSession()->setFlash('success', 'New password was saved.');
167 |
168 | return $this->goHome();
169 | }
170 |
171 | return $this->render('resetPassword', [
172 | 'model' => $model,
173 | ]);
174 | }
175 |
176 | public function actionProduct($id)
177 | {
178 | $model = Product::findOne($id);
179 | if (!isset($model))
180 | throw new NotFoundHttpException('Object not found.');
181 |
182 | return $this->render('product', ['model' => $model]);
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/frontend/models/ContactForm.php:
--------------------------------------------------------------------------------
1 | 'Verification Code',
41 | ];
42 | }
43 |
44 | /**
45 | * Sends an email to the specified email address using the information collected by this model.
46 | *
47 | * @param string $email the target email address
48 | * @return boolean whether the email was sent
49 | */
50 | public function sendEmail($email)
51 | {
52 | return Yii::$app->mailer->compose()
53 | ->setTo($email)
54 | ->setFrom([$this->email => $this->name])
55 | ->setSubject($this->subject)
56 | ->setTextBody($this->body)
57 | ->send();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/frontend/models/PasswordResetRequestForm.php:
--------------------------------------------------------------------------------
1 | 'trim'],
21 | ['email', 'required'],
22 | ['email', 'email'],
23 | ['email', 'exist',
24 | 'targetClass' => '\common\models\User',
25 | 'filter' => ['status' => User::STATUS_ACTIVE],
26 | 'message' => 'There is no user with such email.'
27 | ],
28 | ];
29 | }
30 |
31 | /**
32 | * Sends an email with a link, for resetting the password.
33 | *
34 | * @return boolean whether the email was send
35 | */
36 | public function sendEmail()
37 | {
38 | /* @var $user User */
39 | $user = User::findOne([
40 | 'status' => User::STATUS_ACTIVE,
41 | 'email' => $this->email,
42 | ]);
43 |
44 | if ($user) {
45 | if (!User::isPasswordResetTokenValid($user->password_reset_token)) {
46 | $user->generatePasswordResetToken();
47 | }
48 |
49 | if ($user->save()) {
50 | return \Yii::$app->mailer->compose('passwordResetToken', ['user' => $user])
51 | ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot'])
52 | ->setTo($this->email)
53 | ->setSubject('Password reset for ' . \Yii::$app->name)
54 | ->send();
55 | }
56 | }
57 |
58 | return false;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/frontend/models/ResetPasswordForm.php:
--------------------------------------------------------------------------------
1 | _user = User::findByPasswordResetToken($token);
34 | if (!$this->_user) {
35 | throw new InvalidParamException('Wrong password reset token.');
36 | }
37 | parent::__construct($config);
38 | }
39 |
40 | /**
41 | * @inheritdoc
42 | */
43 | public function rules()
44 | {
45 | return [
46 | ['password', 'required'],
47 | ['password', 'string', 'min' => 6],
48 | ];
49 | }
50 |
51 | /**
52 | * Resets password.
53 | *
54 | * @return boolean if password was reset.
55 | */
56 | public function resetPassword()
57 | {
58 | $user = $this->_user;
59 | $user->password = $this->password;
60 | $user->removePasswordResetToken();
61 |
62 | return $user->save();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/frontend/models/SignupForm.php:
--------------------------------------------------------------------------------
1 | 'trim'],
24 | ['username', 'required'],
25 | ['username', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This username has already been taken.'],
26 | ['username', 'string', 'min' => 2, 'max' => 255],
27 |
28 | ['email', 'filter', 'filter' => 'trim'],
29 | ['email', 'required'],
30 | ['email', 'email'],
31 | ['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This email address has already been taken.'],
32 |
33 | ['password', 'required'],
34 | ['password', 'string', 'min' => 6],
35 | ];
36 | }
37 |
38 | /**
39 | * Signs user up.
40 | *
41 | * @return User|null the saved model or null if saving fails
42 | */
43 | public function signup()
44 | {
45 | if ($this->validate()) {
46 | $user = new User();
47 | $user->username = $this->username;
48 | $user->email = $this->email;
49 | $user->setPassword($this->password);
50 | $user->generateAuthKey();
51 | $user->save();
52 | return $user;
53 | }
54 |
55 | return null;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/frontend/runtime/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/frontend/views/category/index.php:
--------------------------------------------------------------------------------
1 |
4 | category/index
5 |
6 |
7 | You may change the content of this page by modifying
8 | the file = __FILE__; ?>
.
9 |
10 |
--------------------------------------------------------------------------------
/frontend/views/category/view.php:
--------------------------------------------------------------------------------
1 | title = 'Shop Homepage';
7 | ?>
8 |
9 |
10 |
11 |
12 |
13 |
14 | = CategoriesList::widget() ?>
15 |
16 |
17 |
18 | limit(3)->all() as $product)
20 | $items[] = [
21 | 'content' => Html::a(Html::img($product->getImage(), ['alt' => $product->name]), ['site/product', 'id' => $product->id]),
22 | 'caption' => $product->name . ' $' . $product->price,
23 | ]; ?>
24 |
25 |
26 | = \yii\bootstrap\Carousel::widget([
27 | 'items' => $items,
28 | 'options' => ['class' => 'slide'],
29 | 'controls' => [
30 | Html::tag('span', '', ['class' => 'glyphicon glyphicon-chevron-left']),
31 | Html::tag('span', '', ['class' => 'glyphicon glyphicon-chevron-right']),
32 | ],
33 | ]) ?>
34 |
35 |
36 |
37 |
38 |
39 | all() as $product) : ?>
40 |
41 |
42 | = Html::img($product->getImage(), ['alt' => $product->name]) ?>
43 |
44 |
45 |
$= $product->price ?>
46 |
= Html::a($product->name, ['site/product', 'id' => $product->id]) ?>
47 |
48 |
= $product->short_description ?>
49 |
50 |
51 |
15 reviews
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/frontend/views/layouts/main.php:
--------------------------------------------------------------------------------
1 |
14 | beginPage() ?>
15 |
16 |
17 |
18 |
19 |
20 | = Html::csrfMetaTags() ?>
21 | = Html::encode($this->title) ?>
22 | head() ?>
23 |
24 |
25 | beginBody() ?>
26 |
27 | 'My Company',
30 | 'brandUrl' => Yii::$app->homeUrl,
31 | 'options' => [
32 | 'class' => 'navbar-inverse navbar-fixed-top',
33 | ],
34 | ]);
35 | $menuItems = [
36 | ['label' => 'Home', 'url' => ['/site/index']],
37 | ['label' => 'About', 'url' => ['/site/about']],
38 | ['label' => 'Contact', 'url' => ['/site/contact']],
39 | ];
40 | if (Yii::$app->user->isGuest) {
41 | $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']];
42 | $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']];
43 | } else {
44 | $menuItems[] = [
45 | 'label' => 'Logout (' . Yii::$app->user->identity->username . ')',
46 | 'url' => ['/site/logout'],
47 | 'linkOptions' => ['data-method' => 'post']
48 | ];
49 | }
50 | echo Nav::widget([
51 | 'options' => ['class' => 'navbar-nav navbar-right'],
52 | 'items' => $menuItems,
53 | ]);
54 | NavBar::end();
55 | ?>
56 |
57 |
58 | = Breadcrumbs::widget([
59 | 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
60 | ]) ?>
61 | = Alert::widget() ?>
62 | = $content ?>
63 |
64 |
65 |
66 |
72 |
73 | endBody() ?>
74 |
75 |
76 | endPage() ?>
77 |
--------------------------------------------------------------------------------
/frontend/views/site/about.php:
--------------------------------------------------------------------------------
1 | title = 'About';
6 | $this->params['breadcrumbs'][] = $this->title;
7 | ?>
8 |
9 |
= Html::encode($this->title) ?>
10 |
11 |
This is the About page. You may modify the following file to customize its content:
12 |
13 |
= __FILE__ ?>
14 |
15 |
--------------------------------------------------------------------------------
/frontend/views/site/contact.php:
--------------------------------------------------------------------------------
1 | title = 'Contact';
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
38 |
--------------------------------------------------------------------------------
/frontend/views/site/error.php:
--------------------------------------------------------------------------------
1 | title = $name;
11 | ?>
12 |
13 |
14 |
= Html::encode($this->title) ?>
15 |
16 |
17 | = nl2br(Html::encode($message)) ?>
18 |
19 |
20 |
21 | The above error occurred while the Web server was processing your request.
22 |
23 |
24 | Please contact us if you think this is a server error. Thank you.
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/frontend/views/site/index.php:
--------------------------------------------------------------------------------
1 | title = 'Shop Homepage';
10 | ?>
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | = CategoriesList::widget() ?>
19 |
20 |
21 |
22 |
23 | limit(3)->all() as $product) {
25 | /** @var \common\models\Product $product */
26 | $items[] = [
27 | 'content' => Html::a(Html::img($product->getImage(), ['alt' => $product->name]),
28 | ['site/product', 'id' => $product->id]),
29 | 'caption' => $product->name . ' $' . $product->price,
30 | ];
31 | } ?>
32 |
33 |
34 | = \yii\bootstrap\Carousel::widget([
35 | 'items' => $items,
36 | 'options' => ['class' => 'slide'],
37 | 'controls' => [
38 | Html::tag('span', '', ['class' => 'glyphicon glyphicon-chevron-left']),
39 | Html::tag('span', '', ['class' => 'glyphicon glyphicon-chevron-right']),
40 | ],
41 | ]) ?>
42 |
43 |
44 |
45 |
46 |
47 | getModels() as $product) : ?>
48 |
49 |
50 | = Html::img($product->getImage(), ['alt' => $product->name]) ?>
51 |
52 |
53 |
$= $product->price ?>
54 |
= Html::a($product->name, ['site/product', 'id' => $product->id]) ?>
55 |
56 |
= $product->short_description ?>
57 |
58 |
59 |
15 reviews
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/frontend/views/site/login.php:
--------------------------------------------------------------------------------
1 | title = 'Login';
10 | $this->params['breadcrumbs'][] = $this->title;
11 | ?>
12 |
13 |
= Html::encode($this->title) ?>
14 |
15 |
Please fill out the following fields to login:
16 |
17 |
18 |
19 | 'login-form']); ?>
20 | = $form->field($model, 'username') ?>
21 | = $form->field($model, 'password')->passwordInput() ?>
22 | = $form->field($model, 'rememberMe')->checkbox() ?>
23 |
24 | If you forgot your password you can = Html::a('reset it', ['site/request-password-reset']) ?>.
25 |
26 |
27 | = Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/frontend/views/site/product.php:
--------------------------------------------------------------------------------
1 | title = $model->name;
8 | ?>
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | = CategoriesList::widget([]) ?>
17 |
18 |
19 |
20 |
21 |
22 | = Html::img($model->getImage(), ['class' => 'img-responsive', 'alt' => $model->name]) ?>
23 |
24 |
$= $model->price ?>
25 |
27 |
28 |
= $model->long_description ?>
29 |
30 |
31 |
32 |
3 reviews
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 4.0 stars
41 |
42 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | Anonymous
61 |
10 days ago
62 |
63 |
This product was great in terms of quality. I would definitely buy another!
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | Anonymous
77 |
12 days ago
78 |
79 |
I've alredy ordered another one!
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | Anonymous
93 |
15 days ago
94 |
95 |
I've seen some better than this, but not at this price. I definitely recommend this
96 | item.
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/frontend/views/site/requestPasswordResetToken.php:
--------------------------------------------------------------------------------
1 | title = 'Request password reset';
10 | $this->params['breadcrumbs'][] = $this->title;
11 | ?>
12 |
13 |
= Html::encode($this->title) ?>
14 |
15 |
Please fill out your email. A link to reset password will be sent there.
16 |
17 |
18 |
19 | 'request-password-reset-form']); ?>
20 | = $form->field($model, 'email') ?>
21 |
22 | = Html::submitButton('Send', ['class' => 'btn btn-primary']) ?>
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/frontend/views/site/resetPassword.php:
--------------------------------------------------------------------------------
1 | title = 'Reset password';
10 | $this->params['breadcrumbs'][] = $this->title;
11 | ?>
12 |
13 |
= Html::encode($this->title) ?>
14 |
15 |
Please choose your new password:
16 |
17 |
18 |
19 | 'reset-password-form']); ?>
20 | = $form->field($model, 'password')->passwordInput() ?>
21 |
22 | = Html::submitButton('Save', ['class' => 'btn btn-primary']) ?>
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/frontend/views/site/signup.php:
--------------------------------------------------------------------------------
1 | title = 'Signup';
10 | $this->params['breadcrumbs'][] = $this->title;
11 | ?>
12 |
13 |
= Html::encode($this->title) ?>
14 |
15 |
Please fill out the following fields to signup:
16 |
17 |
18 |
19 | 'form-signup']); ?>
20 | = $form->field($model, 'username') ?>
21 | = $form->field($model, 'email') ?>
22 | = $form->field($model, 'password')->passwordInput() ?>
23 |
24 | = Html::submitButton('Signup', ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?>
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/frontend/web/.gitignore:
--------------------------------------------------------------------------------
1 | /index.php
2 | /index-test.php
3 |
--------------------------------------------------------------------------------
/frontend/web/.htaccess:
--------------------------------------------------------------------------------
1 | RewriteEngine on
2 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
3 | RewriteCond %{REQUEST_FILENAME} !-f
4 | RewriteCond %{REQUEST_FILENAME} !-d
5 | RewriteRule . index.php
--------------------------------------------------------------------------------
/frontend/web/assets/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/frontend/web/css/site.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | }
5 |
6 | .wrap {
7 | min-height: 100%;
8 | height: auto;
9 | margin: 0 auto -60px;
10 | padding: 0 0 60px;
11 | }
12 |
13 | .wrap > .container {
14 | padding: 70px 15px 20px;
15 | }
16 |
17 | .footer {
18 | height: 60px;
19 | background-color: #f5f5f5;
20 | border-top: 1px solid #ddd;
21 | padding-top: 20px;
22 | }
23 |
24 | .jumbotron {
25 | text-align: center;
26 | background-color: transparent;
27 | }
28 |
29 | .jumbotron .btn {
30 | font-size: 21px;
31 | padding: 14px 24px;
32 | }
33 |
34 | .not-set {
35 | color: #c55;
36 | font-style: italic;
37 | }
38 |
39 | /* add sorting icons to gridview sort links */
40 | a.asc:after, a.desc:after {
41 | position: relative;
42 | top: 1px;
43 | display: inline-block;
44 | font-family: 'Glyphicons Halflings';
45 | font-style: normal;
46 | font-weight: normal;
47 | line-height: 1;
48 | padding-left: 5px;
49 | }
50 |
51 | a.asc:after {
52 | content: /*"\e113"*/ "\e151";
53 | }
54 |
55 | a.desc:after {
56 | content: /*"\e114"*/ "\e152";
57 | }
58 |
59 | .sort-numerical a.asc:after {
60 | content: "\e153";
61 | }
62 |
63 | .sort-numerical a.desc:after {
64 | content: "\e154";
65 | }
66 |
67 | .sort-ordinal a.asc:after {
68 | content: "\e155";
69 | }
70 |
71 | .sort-ordinal a.desc:after {
72 | content: "\e156";
73 | }
74 |
75 | .grid-view th {
76 | white-space: nowrap;
77 | }
78 |
79 | .hint-block {
80 | display: block;
81 | margin-top: 5px;
82 | color: #999;
83 | }
84 |
85 | .error-summary {
86 | color: #a94442;
87 | background: #fdf7f7;
88 | border-left: 3px solid #eed3d7;
89 | padding: 10px 20px;
90 | margin: 0 0 15px 0;
91 | }
92 |
93 | .slide-image {
94 | width: 100%;
95 | }
96 |
97 | .carousel-holder {
98 | margin-bottom: 30px;
99 | }
100 |
101 | .carousel-control,
102 | .item {
103 | border-radius: 4px;
104 | }
105 |
106 | .caption {
107 | height: 130px;
108 | overflow: hidden;
109 | }
110 |
111 | .caption h4 {
112 | white-space: nowrap;
113 | }
114 |
115 | .thumbnail img {
116 | width: 100%;
117 | }
118 |
119 | .ratings {
120 | padding-right: 10px;
121 | padding-left: 10px;
122 | color: #d17581;
123 | }
124 |
125 | .thumbnail {
126 | padding: 0;
127 | }
128 |
129 | .thumbnail .caption-full {
130 | padding: 9px;
131 | color: #333;
132 | }
133 |
134 |
--------------------------------------------------------------------------------
/frontend/web/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NullRefExcep/yii2-shopper/176e51c5e1a224511119876b11e2e746366a388f/frontend/web/favicon.ico
--------------------------------------------------------------------------------
/frontend/web/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
--------------------------------------------------------------------------------
/frontend/widgets/Alert.php:
--------------------------------------------------------------------------------
1 | getSession()->setFlash('error', 'This is the message');
16 | * \Yii::$app->getSession()->setFlash('success', 'This is the message');
17 | * \Yii::$app->getSession()->setFlash('info', 'This is the message');
18 | * ```
19 | *
20 | * Multiple messages could be set as follows:
21 | *
22 | * ```php
23 | * \Yii::$app->getSession()->setFlash('error', ['Error 1', 'Error 2']);
24 | * ```
25 | *
26 | * @author Kartik Visweswaran
27 | * @author Alexander Makarov
28 | */
29 | class Alert extends \yii\bootstrap\Widget
30 | {
31 | /**
32 | * @var array the alert types configuration for the flash messages.
33 | * This array is setup as $key => $value, where:
34 | * - $key is the name of the session flash variable
35 | * - $value is the bootstrap alert type (i.e. danger, success, info, warning)
36 | */
37 | public $alertTypes = [
38 | 'error' => 'alert-danger',
39 | 'danger' => 'alert-danger',
40 | 'success' => 'alert-success',
41 | 'info' => 'alert-info',
42 | 'warning' => 'alert-warning'
43 | ];
44 |
45 | /**
46 | * @var array the options for rendering the close button tag.
47 | */
48 | public $closeButton = [];
49 |
50 | public function init()
51 | {
52 | parent::init();
53 |
54 | $session = \Yii::$app->getSession();
55 | $flashes = $session->getAllFlashes();
56 | $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : '';
57 |
58 | foreach ($flashes as $type => $data) {
59 | if (isset($this->alertTypes[$type])) {
60 | $data = (array) $data;
61 | foreach ($data as $message) {
62 | /* initialize css class for each alert box */
63 | $this->options['class'] = $this->alertTypes[$type] . $appendCss;
64 |
65 | /* assign unique id to each alert box */
66 | $this->options['id'] = $this->getId() . '-' . $type;
67 |
68 | echo \yii\bootstrap\Alert::widget([
69 | 'body' => $message,
70 | 'closeButton' => $this->closeButton,
71 | 'options' => $this->options,
72 | ]);
73 | }
74 |
75 | $session->removeFlash($type);
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/frontend/widgets/CategoriesList.php:
--------------------------------------------------------------------------------
1 | catalog->getCategories();
14 | return $this->render('categories-list', ['categories' => $categories]);
15 | }
16 |
17 | }
--------------------------------------------------------------------------------
/frontend/widgets/views/categories-list.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
Categories
9 |
10 | = FancytreeWidget::widget([
11 | 'name' => 'category',
12 | 'source' => $categories,
13 | 'clickFolderMode' => FancytreeWidget::CLICK_ACTIVATE_EXPAND,
14 | ]) ?>
15 |
16 |
--------------------------------------------------------------------------------
/init:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 |
11 | *
12 | * @link http://www.yiiframework.com/
13 | * @copyright Copyright (c) 2008 Yii Software LLC
14 | * @license http://www.yiiframework.com/license/
15 | */
16 |
17 | if (!extension_loaded('mcrypt')) {
18 | die('The mcrypt PHP extension is required by Yii2.');
19 | }
20 |
21 | $params = getParams();
22 | $root = str_replace('\\', '/', __DIR__);
23 | $envs = require("$root/environments/index.php");
24 | $envNames = array_keys($envs);
25 |
26 | echo "Yii Application Initialization Tool v1.0\n\n";
27 |
28 | $envName = null;
29 | if (empty($params['env']) || $params['env'] === '1') {
30 | echo "Which environment do you want the application to be initialized in?\n\n";
31 | foreach ($envNames as $i => $name) {
32 | echo " [$i] $name\n";
33 | }
34 | echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
35 | $answer = trim(fgets(STDIN));
36 |
37 | if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) {
38 | echo "\n Quit initialization.\n";
39 | exit(0);
40 | }
41 |
42 | if (isset($envNames[$answer])) {
43 | $envName = $envNames[$answer];
44 | }
45 | } else {
46 | $envName = $params['env'];
47 | }
48 |
49 | if (!in_array($envName, $envNames)) {
50 | $envsList = implode(', ', $envNames);
51 | echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n";
52 | exit(2);
53 | }
54 |
55 | $env = $envs[$envName];
56 |
57 | if (empty($params['env'])) {
58 | echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
59 | $answer = trim(fgets(STDIN));
60 | if (strncasecmp($answer, 'y', 1)) {
61 | echo "\n Quit initialization.\n";
62 | exit(0);
63 | }
64 | }
65 |
66 | echo "\n Start initialization ...\n\n";
67 | $files = getFileList("$root/environments/{$env['path']}");
68 | $all = false;
69 | foreach ($files as $file) {
70 | if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) {
71 | break;
72 | }
73 | }
74 |
75 | $callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable'];
76 | foreach ($callbacks as $callback) {
77 | if (!empty($env[$callback])) {
78 | $callback($root, $env[$callback]);
79 | }
80 | }
81 |
82 | echo "\n ... initialization completed.\n\n";
83 |
84 | function getFileList($root, $basePath = '')
85 | {
86 | $files = [];
87 | $handle = opendir($root);
88 | while (($path = readdir($handle)) !== false) {
89 | if ($path === '.svn' || $path === '.' || $path === '..') {
90 | continue;
91 | }
92 | $fullPath = "$root/$path";
93 | $relativePath = $basePath === '' ? $path : "$basePath/$path";
94 | if (is_dir($fullPath)) {
95 | $files = array_merge($files, getFileList($fullPath, $relativePath));
96 | } else {
97 | $files[] = $relativePath;
98 | }
99 | }
100 | closedir($handle);
101 | return $files;
102 | }
103 |
104 | function copyFile($root, $source, $target, &$all, $params)
105 | {
106 | if (!is_file($root . '/' . $source)) {
107 | echo " skip $target ($source not exist)\n";
108 | return true;
109 | }
110 | if (is_file($root . '/' . $target)) {
111 | if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
112 | echo " unchanged $target\n";
113 | return true;
114 | }
115 | if ($all) {
116 | echo " overwrite $target\n";
117 | } else {
118 | echo " exist $target\n";
119 | echo " ...overwrite? [Yes|No|All|Quit] ";
120 |
121 |
122 | $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN));
123 | if (!strncasecmp($answer, 'q', 1)) {
124 | return false;
125 | } else {
126 | if (!strncasecmp($answer, 'y', 1)) {
127 | echo " overwrite $target\n";
128 | } else {
129 | if (!strncasecmp($answer, 'a', 1)) {
130 | echo " overwrite $target\n";
131 | $all = true;
132 | } else {
133 | echo " skip $target\n";
134 | return true;
135 | }
136 | }
137 | }
138 | }
139 | file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
140 | return true;
141 | }
142 | echo " generate $target\n";
143 | @mkdir(dirname($root . '/' . $target), 0777, true);
144 | file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
145 | return true;
146 | }
147 |
148 | function getParams()
149 | {
150 | $rawParams = [];
151 | if (isset($_SERVER['argv'])) {
152 | $rawParams = $_SERVER['argv'];
153 | array_shift($rawParams);
154 | }
155 |
156 | $params = [];
157 | foreach ($rawParams as $param) {
158 | if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
159 | $name = $matches[1];
160 | $params[$name] = isset($matches[3]) ? $matches[3] : true;
161 | } else {
162 | $params[] = $param;
163 | }
164 | }
165 | return $params;
166 | }
167 |
168 | function setWritable($root, $paths)
169 | {
170 | foreach ($paths as $writable) {
171 | echo " chmod 0777 $writable\n";
172 | @chmod("$root/$writable", 0777);
173 | }
174 | }
175 |
176 | function setExecutable($root, $paths)
177 | {
178 | foreach ($paths as $executable) {
179 | echo " chmod 0755 $executable\n";
180 | @chmod("$root/$executable", 0755);
181 | }
182 | }
183 |
184 | function setCookieValidationKey($root, $paths)
185 | {
186 | foreach ($paths as $file) {
187 | echo " generate cookie validation key in $file\n";
188 | $file = $root . '/' . $file;
189 | $length = 32;
190 | $bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
191 | $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
192 | $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file));
193 | file_put_contents($file, $content);
194 | }
195 | }
196 |
197 | function createSymlink($links)
198 | {
199 | foreach ($links as $link => $target) {
200 | echo " symlink $target as $link\n";
201 | if (!is_link($link)) {
202 | symlink($target, $link);
203 | }
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/requirements.php:
--------------------------------------------------------------------------------
1 | Error';
18 | echo 'The path to yii framework seems to be incorrect.
';
19 | echo 'You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . '.
';
20 | echo 'Please refer to the README on how to install Yii.
';
21 | }
22 |
23 | require_once($frameworkPath . '/requirements/YiiRequirementChecker.php');
24 | $requirementsChecker = new YiiRequirementChecker();
25 |
26 | /**
27 | * Adjust requirements according to your application specifics.
28 | */
29 | $requirements = array(
30 | // Database :
31 | array(
32 | 'name' => 'PDO extension',
33 | 'mandatory' => true,
34 | 'condition' => extension_loaded('pdo'),
35 | 'by' => 'All DB-related classes',
36 | ),
37 | array(
38 | 'name' => 'PDO SQLite extension',
39 | 'mandatory' => false,
40 | 'condition' => extension_loaded('pdo_sqlite'),
41 | 'by' => 'All DB-related classes',
42 | 'memo' => 'Required for SQLite database.',
43 | ),
44 | array(
45 | 'name' => 'PDO MySQL extension',
46 | 'mandatory' => false,
47 | 'condition' => extension_loaded('pdo_mysql'),
48 | 'by' => 'All DB-related classes',
49 | 'memo' => 'Required for MySQL database.',
50 | ),
51 | array(
52 | 'name' => 'PDO PostgreSQL extension',
53 | 'mandatory' => false,
54 | 'condition' => extension_loaded('pdo_pgsql'),
55 | 'by' => 'All DB-related classes',
56 | 'memo' => 'Required for PostgreSQL database.',
57 | ),
58 | // Cache :
59 | array(
60 | 'name' => 'Memcache extension',
61 | 'mandatory' => false,
62 | 'condition' => extension_loaded('memcache') || extension_loaded('memcached'),
63 | 'by' => 'MemCache',
64 | 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true
.' : ''
65 | ),
66 | array(
67 | 'name' => 'APC extension',
68 | 'mandatory' => false,
69 | 'condition' => extension_loaded('apc'),
70 | 'by' => 'ApcCache',
71 | ),
72 | // PHP ini :
73 | 'phpSafeMode' => array(
74 | 'name' => 'PHP safe mode',
75 | 'mandatory' => false,
76 | 'condition' => $requirementsChecker->checkPhpIniOff("safe_mode"),
77 | 'by' => 'File uploading and console command execution',
78 | 'memo' => '"safe_mode" should be disabled at php.ini',
79 | ),
80 | 'phpExposePhp' => array(
81 | 'name' => 'Expose PHP',
82 | 'mandatory' => false,
83 | 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"),
84 | 'by' => 'Security reasons',
85 | 'memo' => '"expose_php" should be disabled at php.ini',
86 | ),
87 | 'phpAllowUrlInclude' => array(
88 | 'name' => 'PHP allow url include',
89 | 'mandatory' => false,
90 | 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"),
91 | 'by' => 'Security reasons',
92 | 'memo' => '"allow_url_include" should be disabled at php.ini',
93 | ),
94 | 'phpSmtp' => array(
95 | 'name' => 'PHP mail SMTP',
96 | 'mandatory' => false,
97 | 'condition' => strlen(ini_get('SMTP')) > 0,
98 | 'by' => 'Email sending',
99 | 'memo' => 'PHP mail SMTP server required',
100 | ),
101 | );
102 | $requirementsChecker->checkYii()->check($requirements)->render();
103 |
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | This directory contains various tests for the advanced applications.
2 |
3 | Tests in `codeception` directory are developed with [Codeception PHP Testing Framework](http://codeception.com/).
4 |
5 | After creating and setting up the advanced application, follow these steps to prepare for the tests:
6 |
7 | 1. Install Codeception if it's not yet installed:
8 |
9 | ```
10 | composer global require "codeception/codeception=2.0.*" "codeception/specify=*" "codeception/verify=*"
11 | ```
12 |
13 | If you've never used Composer for global packages run `composer global status`. It should output:
14 |
15 | ```
16 | Changed current directory to
17 | ```
18 |
19 | Then add `/vendor/bin` to you `PATH` environment variable. Now you're able to use `codecept` from command
20 | line globally.
21 |
22 | 2. Install faker extension by running the following from template root directory where `composer.json` is:
23 |
24 | ```
25 | composer require --dev yiisoft/yii2-faker:*
26 | ```
27 |
28 | 3. Create `yii2_advanced_tests` database then update it by applying migrations:
29 |
30 | ```
31 | codeception/bin/yii migrate
32 | ```
33 |
34 | 4. In order to be able to run acceptance tests you need to start a webserver. The simplest way is to use PHP built in
35 | webserver. In the root directory where `common`, `frontend` etc. are execute the following:
36 |
37 | ```
38 | php -S localhost:8080
39 | ```
40 |
41 | 5. Now you can run the tests with the following commands, assuming you are in the `tests/codeception` directory:
42 |
43 | ```
44 | # frontend tests
45 | cd frontend
46 | codecept build
47 | codecept run
48 |
49 | # backend tests
50 |
51 | cd backend
52 | codecept build
53 | codecept run
54 |
55 | # etc.
56 | ```
57 |
58 | If you already have run `codecept build` for each application, you can skip that step and run all tests by a single `codecept run`.
59 |
--------------------------------------------------------------------------------
/tests/codeception.yml:
--------------------------------------------------------------------------------
1 | include:
2 | - codeception/common
3 | - codeception/console
4 | - codeception/backend
5 | - codeception/frontend
6 |
7 | paths:
8 | log: codeception/_output
9 |
10 | settings:
11 | colors: true
12 |
--------------------------------------------------------------------------------
/tests/codeception/_output/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/tests/codeception/backend/.gitignore:
--------------------------------------------------------------------------------
1 | # these files are auto generated by codeception build
2 | /unit/UnitTester.php
3 | /functional/FunctionalTester.php
4 | /acceptance/AcceptanceTester.php
5 |
--------------------------------------------------------------------------------
/tests/codeception/backend/_bootstrap.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure login page works');
8 |
9 | $loginPage = LoginPage::openBy($I);
10 |
11 | $I->amGoingTo('submit login form with no data');
12 | $loginPage->login('', '');
13 | $I->expectTo('see validations errors');
14 | $I->see('Username cannot be blank.', '.help-block');
15 | $I->see('Password cannot be blank.', '.help-block');
16 |
17 | $I->amGoingTo('try to login with wrong credentials');
18 | $I->expectTo('see validations errors');
19 | $loginPage->login('admin', 'wrong');
20 | $I->expectTo('see validations errors');
21 | $I->see('Incorrect username or password.', '.help-block');
22 |
23 | $I->amGoingTo('try to login with correct credentials');
24 | $loginPage->login('erau', 'password_0');
25 | $I->expectTo('see that user is logged');
26 | $I->seeLink('Logout (erau)');
27 | $I->dontSeeLink('Login');
28 | $I->dontSeeLink('Signup');
29 | /** Uncomment if using WebDriver
30 | * $I->click('Logout (erau)');
31 | * $I->dontSeeLink('Logout (erau)');
32 | * $I->seeLink('Login');
33 | */
34 |
--------------------------------------------------------------------------------
/tests/codeception/backend/acceptance/_bootstrap.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure login page works');
8 |
9 | $loginPage = LoginPage::openBy($I);
10 |
11 | $I->amGoingTo('submit login form with no data');
12 | $loginPage->login('', '');
13 | $I->expectTo('see validations errors');
14 | $I->see('Username cannot be blank.', '.help-block');
15 | $I->see('Password cannot be blank.', '.help-block');
16 |
17 | $I->amGoingTo('try to login with wrong credentials');
18 | $I->expectTo('see validations errors');
19 | $loginPage->login('admin', 'wrong');
20 | $I->expectTo('see validations errors');
21 | $I->see('Incorrect username or password.', '.help-block');
22 |
23 | $I->amGoingTo('try to login with correct credentials');
24 | $loginPage->login('erau', 'password_0');
25 | $I->expectTo('see that user is logged');
26 | $I->seeLink('Logout (erau)');
27 | $I->dontSeeLink('Login');
28 | $I->dontSeeLink('Signup');
29 |
--------------------------------------------------------------------------------
/tests/codeception/backend/functional/_bootstrap.php:
--------------------------------------------------------------------------------
1 | [
21 | 'fixture' => [
22 | 'class' => 'yii\faker\FixtureController',
23 | 'fixtureDataPath' => '@tests/codeception/common/fixtures/data',
24 | 'templatePath' => '@tests/codeception/common/templates/fixtures',
25 | ],
26 | ],
27 | ]
28 | );
29 |
30 | $application = new yii\console\Application($config);
31 | $exitCode = $application->run();
32 | exit($exitCode);
33 |
--------------------------------------------------------------------------------
/tests/codeception/bin/yii.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | rem -------------------------------------------------------------
4 | rem Yii command line bootstrap script for Windows.
5 | rem
6 | rem @author Qiang Xue
7 | rem @link http://www.yiiframework.com/
8 | rem @copyright Copyright (c) 2008 Yii Software LLC
9 | rem @license http://www.yiiframework.com/license/
10 | rem -------------------------------------------------------------
11 |
12 | @setlocal
13 |
14 | set YII_PATH=%~dp0
15 |
16 | if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
17 |
18 | "%PHP_COMMAND%" "%YII_PATH%yii_acceptance" %*
19 |
20 | @endlocal
21 |
--------------------------------------------------------------------------------
/tests/codeception/common/.gitignore:
--------------------------------------------------------------------------------
1 | # these files are auto generated by codeception build
2 | /unit/UnitTester.php
3 | /functional/FunctionalTester.php
4 | /acceptance/AcceptanceTester.php
5 |
--------------------------------------------------------------------------------
/tests/codeception/common/_bootstrap.php:
--------------------------------------------------------------------------------
1 | actor->fillField('input[name="LoginForm[username]"]', $username);
22 | $this->actor->fillField('input[name="LoginForm[password]"]', $password);
23 | $this->actor->click('login-button');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/codeception/common/_support/FixtureHelper.php:
--------------------------------------------------------------------------------
1 | loadFixtures();
38 | }
39 |
40 | /**
41 | * Method is called after all suite tests run
42 | */
43 | public function _afterSuite()
44 | {
45 | $this->unloadFixtures();
46 | }
47 |
48 | /**
49 | * @inheritdoc
50 | */
51 | public function fixtures()
52 | {
53 | return [
54 | 'user' => [
55 | 'class' => UserFixture::className(),
56 | 'dataFile' => '@tests/codeception/common/fixtures/data/init_login.php',
57 | ],
58 | ];
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/tests/codeception/common/codeception.yml:
--------------------------------------------------------------------------------
1 | namespace: tests\codeception\common
2 | actor: Tester
3 | paths:
4 | tests: .
5 | log: _output
6 | data: _data
7 | helpers: _support
8 | settings:
9 | bootstrap: _bootstrap.php
10 | suite_class: \PHPUnit_Framework_TestSuite
11 | colors: true
12 | memory_limit: 1024M
13 | log: true
14 |
--------------------------------------------------------------------------------
/tests/codeception/common/fixtures/UserFixture.php:
--------------------------------------------------------------------------------
1 | 'erau',
6 | 'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI',
7 | // password_0
8 | 'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne',
9 | 'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490',
10 | 'created_at' => '1392559490',
11 | 'updated_at' => '1392559490',
12 | 'email' => 'sfriesen@jenkins.info',
13 | ],
14 | ];
15 |
--------------------------------------------------------------------------------
/tests/codeception/common/templates/fixtures/user.php:
--------------------------------------------------------------------------------
1 | getSecurity();
8 |
9 | return [
10 | 'username' => $faker->userName,
11 | 'email' => $faker->email,
12 | 'auth_key' => $security->generateRandomString(),
13 | 'password_hash' => $security->generatePasswordHash('password_' . $index),
14 | 'password_reset_token' => $security->generateRandomString() . '_' . time(),
15 | 'created_at' => time(),
16 | 'updated_at' => time(),
17 | ];
18 |
--------------------------------------------------------------------------------
/tests/codeception/common/unit.suite.yml:
--------------------------------------------------------------------------------
1 | # Codeception Test Suite Configuration
2 |
3 | # suite for unit (internal) tests.
4 | # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
5 |
6 | class_name: UnitTester
7 |
--------------------------------------------------------------------------------
/tests/codeception/common/unit/DbTestCase.php:
--------------------------------------------------------------------------------
1 | 'bayer.hudson',
6 | 'auth_key' => 'HP187Mvq7Mmm3CTU80dLkGmni_FUH_lR',
7 | //password_0
8 | 'password_hash' => '$2y$13$EjaPFBnZOQsHdGuHI.xvhuDp1fHpo8hKRSk6yshqa9c5EG8s3C3lO',
9 | 'password_reset_token' => 'ExzkCOaYc1L8IOBs4wdTGGbgNiG3Wz1I_1402312317',
10 | 'created_at' => '1402312317',
11 | 'updated_at' => '1402312317',
12 | 'email' => 'nicole.paucek@schultz.info',
13 | ],
14 | ];
15 |
--------------------------------------------------------------------------------
/tests/codeception/common/unit/models/LoginFormTest.php:
--------------------------------------------------------------------------------
1 | [
25 | 'user' => [
26 | 'class' => 'yii\web\User',
27 | 'identityClass' => 'common\models\User',
28 | ],
29 | ],
30 | ]);
31 | }
32 |
33 | protected function tearDown()
34 | {
35 | Yii::$app->user->logout();
36 | parent::tearDown();
37 | }
38 |
39 | public function testLoginNoUser()
40 | {
41 | $model = new LoginForm([
42 | 'username' => 'not_existing_username',
43 | 'password' => 'not_existing_password',
44 | ]);
45 |
46 | $this->specify('user should not be able to login, when there is no identity', function () use ($model) {
47 | expect('model should not login user', $model->login())->false();
48 | expect('user should not be logged in', Yii::$app->user->isGuest)->true();
49 | });
50 | }
51 |
52 | public function testLoginWrongPassword()
53 | {
54 | $model = new LoginForm([
55 | 'username' => 'bayer.hudson',
56 | 'password' => 'wrong_password',
57 | ]);
58 |
59 | $this->specify('user should not be able to login with wrong password', function () use ($model) {
60 | expect('model should not login user', $model->login())->false();
61 | expect('error message should be set', $model->errors)->hasKey('password');
62 | expect('user should not be logged in', Yii::$app->user->isGuest)->true();
63 | });
64 | }
65 |
66 | public function testLoginCorrect()
67 | {
68 |
69 | $model = new LoginForm([
70 | 'username' => 'bayer.hudson',
71 | 'password' => 'password_0',
72 | ]);
73 |
74 | $this->specify('user should be able to login with correct credentials', function () use ($model) {
75 | expect('model should login user', $model->login())->true();
76 | expect('error message should not be set', $model->errors)->hasntKey('password');
77 | expect('user should be logged in', Yii::$app->user->isGuest)->false();
78 | });
79 | }
80 |
81 | /**
82 | * @inheritdoc
83 | */
84 | public function fixtures()
85 | {
86 | return [
87 | 'user' => [
88 | 'class' => UserFixture::className(),
89 | 'dataFile' => '@tests/codeception/common/unit/fixtures/data/models/user.php'
90 | ],
91 | ];
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/tests/codeception/config/acceptance.php:
--------------------------------------------------------------------------------
1 | 'app-common',
12 | 'basePath' => dirname(__DIR__),
13 | ]
14 | );
15 |
--------------------------------------------------------------------------------
/tests/codeception/config/config.php:
--------------------------------------------------------------------------------
1 | [
7 | 'db' => [
8 | 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_tests',
9 | ],
10 | 'mailer' => [
11 | 'useFileTransport' => true,
12 | ],
13 | 'urlManager' => [
14 | 'showScriptName' => true,
15 | ],
16 | ],
17 | ];
18 |
--------------------------------------------------------------------------------
/tests/codeception/config/console/unit.php:
--------------------------------------------------------------------------------
1 | $value) {
21 | $inputType = $field === 'body' ? 'textarea' : 'input';
22 | $this->actor->fillField($inputType . '[name="ContactForm[' . $field . ']"]', $value);
23 | }
24 | $this->actor->click('contact-button');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/_pages/SignupPage.php:
--------------------------------------------------------------------------------
1 | $value) {
22 | $inputType = $field === 'body' ? 'textarea' : 'input';
23 | $this->actor->fillField($inputType . '[name="SignupForm[' . $field . ']"]', $value);
24 | }
25 | $this->actor->click('signup-button');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/acceptance.suite.yml:
--------------------------------------------------------------------------------
1 | # Codeception Test Suite Configuration
2 |
3 | # suite for acceptance tests.
4 | # perform tests in browser using the Selenium-like tools.
5 | # powered by Mink (http://mink.behat.org).
6 | # (tip: that's what your customer will see).
7 | # (tip: test your ajax and javascript by one of Mink drivers).
8 |
9 | # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
10 |
11 | class_name: AcceptanceTester
12 | modules:
13 | enabled:
14 | - PhpBrowser
15 | - tests\codeception\common\_support\FixtureHelper
16 | # you can use WebDriver instead of PhpBrowser to test javascript and ajax.
17 | # This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium
18 | # "restart" option is used by the WebDriver to start each time per test-file new session and cookies,
19 | # it is useful if you want to login in your app in each test.
20 | # - WebDriver
21 | config:
22 | PhpBrowser:
23 | url: 'http://localhost:8080'
24 | # WebDriver:
25 | # url: 'http://localhost'
26 | # browser: firefox
27 | # restart: true
28 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/acceptance/AboutCept.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure that about works');
7 | AboutPage::openBy($I);
8 | $I->see('About', 'h1');
9 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/acceptance/ContactCept.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure that contact works');
7 |
8 | $contactPage = ContactPage::openBy($I);
9 |
10 | $I->see('Contact', 'h1');
11 |
12 | $I->amGoingTo('submit contact form with no data');
13 | $contactPage->submit([]);
14 | $I->expectTo('see validations errors');
15 | $I->see('Contact', 'h1');
16 | $I->see('Name cannot be blank', '.help-block');
17 | $I->see('Email cannot be blank', '.help-block');
18 | $I->see('Subject cannot be blank', '.help-block');
19 | $I->see('Body cannot be blank', '.help-block');
20 | $I->see('The verification code is incorrect', '.help-block');
21 |
22 | $I->amGoingTo('submit contact form with not correct email');
23 | $contactPage->submit([
24 | 'name' => 'tester',
25 | 'email' => 'tester.email',
26 | 'subject' => 'test subject',
27 | 'body' => 'test content',
28 | 'verifyCode' => 'testme',
29 | ]);
30 | $I->expectTo('see that email adress is wrong');
31 | $I->dontSee('Name cannot be blank', '.help-block');
32 | $I->see('Email is not a valid email address.', '.help-block');
33 | $I->dontSee('Subject cannot be blank', '.help-block');
34 | $I->dontSee('Body cannot be blank', '.help-block');
35 | $I->dontSee('The verification code is incorrect', '.help-block');
36 |
37 | $I->amGoingTo('submit contact form with correct data');
38 | $contactPage->submit([
39 | 'name' => 'tester',
40 | 'email' => 'tester@example.com',
41 | 'subject' => 'test subject',
42 | 'body' => 'test content',
43 | 'verifyCode' => 'testme',
44 | ]);
45 | $I->see('Thank you for contacting us. We will respond to you as soon as possible.');
46 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/acceptance/HomeCept.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure that home page works');
6 | $I->amOnPage(Yii::$app->homeUrl);
7 | $I->see('My Company');
8 | $I->seeLink('About');
9 | $I->click('About');
10 | $I->see('This is the About page.');
11 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/acceptance/LoginCept.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure login page works');
7 |
8 | $loginPage = LoginPage::openBy($I);
9 |
10 | $I->amGoingTo('submit login form with no data');
11 | $loginPage->login('', '');
12 | $I->expectTo('see validations errors');
13 | $I->see('Username cannot be blank.', '.help-block');
14 | $I->see('Password cannot be blank.', '.help-block');
15 |
16 | $I->amGoingTo('try to login with wrong credentials');
17 | $I->expectTo('see validations errors');
18 | $loginPage->login('admin', 'wrong');
19 | $I->expectTo('see validations errors');
20 | $I->see('Incorrect username or password.', '.help-block');
21 |
22 | $I->amGoingTo('try to login with correct credentials');
23 | $loginPage->login('erau', 'password_0');
24 | $I->expectTo('see that user is logged');
25 | $I->seeLink('Logout (erau)');
26 | $I->dontSeeLink('Login');
27 | $I->dontSeeLink('Signup');
28 | /** Uncomment if using WebDriver
29 | * $I->click('Logout (erau)');
30 | * $I->dontSeeLink('Logout (erau)');
31 | * $I->seeLink('Login');
32 | */
33 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/acceptance/SignupCest.php:
--------------------------------------------------------------------------------
1 | 'tester.email@example.com',
27 | 'username' => 'tester',
28 | ]);
29 | }
30 |
31 | /**
32 | * This method is called when test fails.
33 | * @param \Codeception\Event\FailEvent $event
34 | */
35 | public function _fail($event)
36 | {
37 | }
38 |
39 | /**
40 | * @param \codeception_frontend\AcceptanceTester $I
41 | * @param \Codeception\Scenario $scenario
42 | */
43 | public function testUserSignup($I, $scenario)
44 | {
45 | $I->wantTo('ensure that signup works');
46 |
47 | $signupPage = SignupPage::openBy($I);
48 | $I->see('Signup', 'h1');
49 | $I->see('Please fill out the following fields to signup:');
50 |
51 | $I->amGoingTo('submit signup form with no data');
52 |
53 | $signupPage->submit([]);
54 |
55 | $I->expectTo('see validation errors');
56 | $I->see('Username cannot be blank.', '.help-block');
57 | $I->see('Email cannot be blank.', '.help-block');
58 | $I->see('Password cannot be blank.', '.help-block');
59 |
60 | $I->amGoingTo('submit signup form with not correct email');
61 | $signupPage->submit([
62 | 'username' => 'tester',
63 | 'email' => 'tester.email',
64 | 'password' => 'tester_password',
65 | ]);
66 |
67 | $I->expectTo('see that email address is wrong');
68 | $I->dontSee('Username cannot be blank.', '.help-block');
69 | $I->dontSee('Password cannot be blank.', '.help-block');
70 | $I->see('Email is not a valid email address.', '.help-block');
71 |
72 | $I->amGoingTo('submit signup form with correct email');
73 | $signupPage->submit([
74 | 'username' => 'tester',
75 | 'email' => 'tester.email@example.com',
76 | 'password' => 'tester_password',
77 | ]);
78 |
79 | $I->expectTo('see that user logged in');
80 | $I->seeLink('Logout (tester)');
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/acceptance/_bootstrap.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure that about works');
7 | AboutPage::openBy($I);
8 | $I->see('About', 'h1');
9 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/functional/ContactCept.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure that contact works');
7 |
8 | $contactPage = ContactPage::openBy($I);
9 |
10 | $I->see('Contact', 'h1');
11 |
12 | $I->amGoingTo('submit contact form with no data');
13 | $contactPage->submit([]);
14 | $I->expectTo('see validations errors');
15 | $I->see('Contact', 'h1');
16 | $I->see('Name cannot be blank', '.help-block');
17 | $I->see('Email cannot be blank', '.help-block');
18 | $I->see('Subject cannot be blank', '.help-block');
19 | $I->see('Body cannot be blank', '.help-block');
20 | $I->see('The verification code is incorrect', '.help-block');
21 |
22 | $I->amGoingTo('submit contact form with not correct email');
23 | $contactPage->submit([
24 | 'name' => 'tester',
25 | 'email' => 'tester.email',
26 | 'subject' => 'test subject',
27 | 'body' => 'test content',
28 | 'verifyCode' => 'testme',
29 | ]);
30 | $I->expectTo('see that email adress is wrong');
31 | $I->dontSee('Name cannot be blank', '.help-block');
32 | $I->see('Email is not a valid email address.', '.help-block');
33 | $I->dontSee('Subject cannot be blank', '.help-block');
34 | $I->dontSee('Body cannot be blank', '.help-block');
35 | $I->dontSee('The verification code is incorrect', '.help-block');
36 |
37 | $I->amGoingTo('submit contact form with correct data');
38 | $contactPage->submit([
39 | 'name' => 'tester',
40 | 'email' => 'tester@example.com',
41 | 'subject' => 'test subject',
42 | 'body' => 'test content',
43 | 'verifyCode' => 'testme',
44 | ]);
45 | $I->see('Thank you for contacting us. We will respond to you as soon as possible.');
46 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/functional/HomeCept.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure that home page works');
5 | $I->amOnPage(Yii::$app->homeUrl);
6 | $I->see('My Company');
7 | $I->seeLink('About');
8 | $I->click('About');
9 | $I->see('This is the About page.');
10 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/functional/LoginCept.php:
--------------------------------------------------------------------------------
1 | wantTo('ensure login page works');
7 |
8 | $loginPage = LoginPage::openBy($I);
9 |
10 | $I->amGoingTo('submit login form with no data');
11 | $loginPage->login('', '');
12 | $I->expectTo('see validations errors');
13 | $I->see('Username cannot be blank.', '.help-block');
14 | $I->see('Password cannot be blank.', '.help-block');
15 |
16 | $I->amGoingTo('try to login with wrong credentials');
17 | $I->expectTo('see validations errors');
18 | $loginPage->login('admin', 'wrong');
19 | $I->expectTo('see validations errors');
20 | $I->see('Incorrect username or password.', '.help-block');
21 |
22 | $I->amGoingTo('try to login with correct credentials');
23 | $loginPage->login('erau', 'password_0');
24 | $I->expectTo('see that user is logged');
25 | $I->seeLink('Logout (erau)');
26 | $I->dontSeeLink('Login');
27 | $I->dontSeeLink('Signup');
28 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/functional/SignupCest.php:
--------------------------------------------------------------------------------
1 | 'tester.email@example.com',
27 | 'username' => 'tester',
28 | ]);
29 | }
30 |
31 | /**
32 | * This method is called when test fails.
33 | * @param \Codeception\Event\FailEvent $event
34 | */
35 | public function _fail($event)
36 | {
37 |
38 | }
39 |
40 | /**
41 | *
42 | * @param \codeception_frontend\FunctionalTester $I
43 | * @param \Codeception\Scenario $scenario
44 | */
45 | public function testUserSignup($I, $scenario)
46 | {
47 | $I->wantTo('ensure that signup works');
48 |
49 | $signupPage = SignupPage::openBy($I);
50 | $I->see('Signup', 'h1');
51 | $I->see('Please fill out the following fields to signup:');
52 |
53 | $I->amGoingTo('submit signup form with no data');
54 |
55 | $signupPage->submit([]);
56 |
57 | $I->expectTo('see validation errors');
58 | $I->see('Username cannot be blank.', '.help-block');
59 | $I->see('Email cannot be blank.', '.help-block');
60 | $I->see('Password cannot be blank.', '.help-block');
61 |
62 | $I->amGoingTo('submit signup form with not correct email');
63 | $signupPage->submit([
64 | 'username' => 'tester',
65 | 'email' => 'tester.email',
66 | 'password' => 'tester_password',
67 | ]);
68 |
69 | $I->expectTo('see that email address is wrong');
70 | $I->dontSee('Username cannot be blank.', '.help-block');
71 | $I->dontSee('Password cannot be blank.', '.help-block');
72 | $I->see('Email is not a valid email address.', '.help-block');
73 |
74 | $I->amGoingTo('submit signup form with correct email');
75 | $signupPage->submit([
76 | 'username' => 'tester',
77 | 'email' => 'tester.email@example.com',
78 | 'password' => 'tester_password',
79 | ]);
80 |
81 | $I->expectTo('see that user is created');
82 | $I->seeRecord('common\models\User', [
83 | 'username' => 'tester',
84 | 'email' => 'tester.email@example.com',
85 | ]);
86 |
87 | $I->expectTo('see that user logged in');
88 | $I->seeLink('Logout (tester)');
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/functional/_bootstrap.php:
--------------------------------------------------------------------------------
1 | 'okirlin',
6 | 'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv',
7 | 'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi',
8 | 'password_reset_token' => 't5GU9NwpuGYSfb7FEZMAxqtuz2PkEvv_' . time(),
9 | 'created_at' => '1391885313',
10 | 'updated_at' => '1391885313',
11 | 'email' => 'brady.renner@rutherford.com',
12 | ],
13 | [
14 | 'username' => 'troy.becker',
15 | 'auth_key' => 'EdKfXrx88weFMV0vIxuTMWKgfK2tS3Lp',
16 | 'password_hash' => '$2y$13$g5nv41Px7VBqhS3hVsVN2.MKfgT3jFdkXEsMC4rQJLfaMa7VaJqL2',
17 | 'password_reset_token' => '4BSNyiZNAuxjs5Mty990c47sVrgllIi_' . time(),
18 | 'created_at' => '1391885313',
19 | 'updated_at' => '1391885313',
20 | 'email' => 'nicolas.dianna@hotmail.com',
21 | 'status' => '0',
22 | ],
23 | ];
24 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/unit/models/ContactFormTest.php:
--------------------------------------------------------------------------------
1 | mailer->fileTransportCallback = function ($mailer, $message) {
18 | return 'testing_message.eml';
19 | };
20 | }
21 |
22 | protected function tearDown()
23 | {
24 | unlink($this->getMessageFile());
25 | parent::tearDown();
26 | }
27 |
28 | public function testContact()
29 | {
30 | $model = new ContactForm();
31 |
32 | $model->attributes = [
33 | 'name' => 'Tester',
34 | 'email' => 'tester@example.com',
35 | 'subject' => 'very important letter subject',
36 | 'body' => 'body of current message',
37 | ];
38 |
39 | $model->sendEmail('admin@example.com');
40 |
41 | $this->specify('email should be send', function () {
42 | expect('email file should exist', file_exists($this->getMessageFile()))->true();
43 | });
44 |
45 | $this->specify('message should contain correct data', function () use ($model) {
46 | $emailMessage = file_get_contents($this->getMessageFile());
47 |
48 | expect('email should contain user name', $emailMessage)->contains($model->name);
49 | expect('email should contain sender email', $emailMessage)->contains($model->email);
50 | expect('email should contain subject', $emailMessage)->contains($model->subject);
51 | expect('email should contain body', $emailMessage)->contains($model->body);
52 | });
53 | }
54 |
55 | private function getMessageFile()
56 | {
57 | return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml';
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/unit/models/PasswordResetRequestFormTest.php:
--------------------------------------------------------------------------------
1 | mailer->fileTransportCallback = function ($mailer, $message) {
21 | return 'testing_message.eml';
22 | };
23 | }
24 |
25 | protected function tearDown()
26 | {
27 | @unlink($this->getMessageFile());
28 |
29 | parent::tearDown();
30 | }
31 |
32 | public function testSendEmailWrongUser()
33 | {
34 | $this->specify('no user with such email, message should not be send', function () {
35 |
36 | $model = new PasswordResetRequestForm();
37 | $model->email = 'not-existing-email@example.com';
38 |
39 | expect('email not send', $model->sendEmail())->false();
40 |
41 | });
42 |
43 | $this->specify('user is not active, message should not be send', function () {
44 |
45 | $model = new PasswordResetRequestForm();
46 | $model->email = $this->user[1]['email'];
47 |
48 | expect('email not send', $model->sendEmail())->false();
49 |
50 | });
51 | }
52 |
53 | public function testSendEmailCorrectUser()
54 | {
55 | $model = new PasswordResetRequestForm();
56 | $model->email = $this->user[0]['email'];
57 | $user = User::findOne(['password_reset_token' => $this->user[0]['password_reset_token']]);
58 |
59 | expect('email sent', $model->sendEmail())->true();
60 | expect('user has valid token', $user->password_reset_token)->notNull();
61 |
62 | $this->specify('message has correct format', function () use ($model) {
63 |
64 | expect('message file exists', file_exists($this->getMessageFile()))->true();
65 |
66 | $message = file_get_contents($this->getMessageFile());
67 | expect('message "from" is correct', $message)->contains(Yii::$app->params['supportEmail']);
68 | expect('message "to" is correct', $message)->contains($model->email);
69 |
70 | });
71 | }
72 |
73 | public function fixtures()
74 | {
75 | return [
76 | 'user' => [
77 | 'class' => UserFixture::className(),
78 | 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php'
79 | ],
80 | ];
81 | }
82 |
83 | private function getMessageFile()
84 | {
85 | return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml';
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/unit/models/ResetPasswordFormTest.php:
--------------------------------------------------------------------------------
1 | user[0]['password_reset_token']);
31 | expect('password should be resetted', $form->resetPassword())->true();
32 | }
33 |
34 | public function fixtures()
35 | {
36 | return [
37 | 'user' => [
38 | 'class' => UserFixture::className(),
39 | 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php'
40 | ],
41 | ];
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/tests/codeception/frontend/unit/models/SignupFormTest.php:
--------------------------------------------------------------------------------
1 | 'some_username',
19 | 'email' => 'some_email@example.com',
20 | 'password' => 'some_password',
21 | ]);
22 |
23 | $user = $model->signup();
24 |
25 | $this->assertInstanceOf('common\models\User', $user, 'user should be valid');
26 |
27 | expect('username should be correct', $user->username)->equals('some_username');
28 | expect('email should be correct', $user->email)->equals('some_email@example.com');
29 | expect('password should be correct', $user->validatePassword('some_password'))->true();
30 | }
31 |
32 | public function testNotCorrectSignup()
33 | {
34 | $model = new SignupForm([
35 | 'username' => 'troy.becker',
36 | 'email' => 'nicolas.dianna@hotmail.com',
37 | 'password' => 'some_password',
38 | ]);
39 |
40 | expect('username and email are in use, user should not be created', $model->signup())->null();
41 | }
42 |
43 | public function fixtures()
44 | {
45 | return [
46 | 'user' => [
47 | 'class' => UserFixture::className(),
48 | 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php',
49 | ],
50 | ];
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------