├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── UPGRADE.md
├── composer.json
└── src
├── ActionEvent.php
├── CrudController.php
├── actions
├── Action.php
├── Callback.php
├── Create.php
├── Delete.php
├── FlushCache.php
├── Index.php
├── ModelFormTrait.php
├── Position.php
├── Restore.php
├── RoleCreate.php
├── RoleUpdate.php
├── SafeDelete.php
├── SoftDelete.php
├── Update.php
├── VariationCreate.php
├── VariationUpdate.php
└── View.php
├── behaviors
├── ContextModelControlBehavior.php
├── ModelControlBehavior.php
└── action
│ ├── RoleBehavior.php
│ └── VariationBehavior.php
├── gii
├── crud
│ ├── Generator.php
│ ├── default
│ │ ├── controller.php
│ │ ├── search.php
│ │ └── views
│ │ │ ├── _form.php
│ │ │ ├── _search.php
│ │ │ ├── create.php
│ │ │ ├── index.php
│ │ │ ├── update.php
│ │ │ └── view.php
│ └── form.php
└── mainframe
│ ├── Generator.php
│ ├── default
│ ├── controller.php
│ ├── layouts
│ │ ├── main.php
│ │ ├── mainMenu.php
│ │ └── overall.php
│ └── views
│ │ ├── error.php
│ │ ├── index.php
│ │ └── login.php
│ └── form.php
├── grid
├── ActionColumn.php
├── DeleteStatusColumn.php
├── PositionColumn.php
└── VariationColumn.php
├── messages
├── config.php
├── en
│ └── yii2tech-admin.php
├── es
│ └── yii2tech-admin.php
├── it
│ └── yii2tech-admin.php
├── pt-BR
│ └── yii2tech-admin.php
├── ru
│ └── yii2tech-admin.php
└── uk
│ └── yii2tech-admin.php
└── widgets
├── ActionAlert.php
├── Alert.php
├── ButtonContextMenu.php
└── Nav.php
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Yii 2 Admin pack extension Change Log
2 | =====================================
3 |
4 | 1.1.0, April 9, 2018
5 | --------------------
6 |
7 | - Enh #18: Removed `yii\base\Object::className()` in favor of native PHP syntax `::class`, which does not trigger autoloading (klimov-paul)
8 |
9 |
10 | 1.0.3, April 9, 2018
11 | --------------------
12 |
13 | - Enh #17: Widget `yii2tech\admin\widgets\Alert` now determines alert type using wildcard match (klimov-paul)
14 |
15 |
16 | 1.0.2, November 3, 2017
17 | -----------------------
18 |
19 | - Enh #15: Added controller and actions references in doc blocks for view files generated by Gii 'CRUD' generator (naffiq, klimov-paul)
20 |
21 |
22 | 1.0.1, April 19, 2017
23 | ---------------------
24 |
25 | - Enh #14: Widget `yii2tech\admin\widgets\ActionAlert` created (klimov-paul)
26 | - Enh: Widget `yii2tech\admin\widgets\Alert` refactored allowing `run()` method to return an output instead of using `echo` (klimov-paul)
27 |
28 |
29 | 1.0.0, January 6, 2017
30 | ----------------------
31 |
32 | - Initial release.
33 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The Yii framework is free software. It is released under the terms of
2 | the following BSD License.
3 |
4 | Copyright © 2015 by Yii2tech (https://github.com/yii2tech)
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions
9 | are met:
10 |
11 | * Redistributions of source code must retain the above copyright
12 | notice, this list of conditions and the following disclaimer.
13 | * Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in
15 | the documentation and/or other materials provided with the
16 | distribution.
17 | * Neither the name of Yii2tech nor the names of its
18 | contributors may be used to endorse or promote products derived
19 | from this software without specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | POSSIBILITY OF SUCH DAMAGE.
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Admin pack for Yii 2
6 |
7 |
8 |
9 | This extension provides controllers, actions, widgets and other tools for administration panel creation in Yii2 project.
10 |
11 | For license information check the [LICENSE](LICENSE.md)-file.
12 |
13 | [](https://packagist.org/packages/yii2tech/admin)
14 | [](https://packagist.org/packages/yii2tech/admin)
15 | [](https://travis-ci.org/yii2tech/admin)
16 |
17 |
18 | Installation
19 | ------------
20 |
21 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
22 |
23 | Either run
24 |
25 | ```
26 | php composer.phar require --prefer-dist yii2tech/admin
27 | ```
28 |
29 | or add
30 |
31 | ```json
32 | "yii2tech/admin": "*"
33 | ```
34 |
35 | to the require section of your composer.json.
36 |
37 |
38 | Usage
39 | -----
40 |
41 | This extension provides controllers, actions, widgets and other tools for administration panel creation in Yii2 project.
42 | These tools are meant to be used together for the rapid web application administration panel composition.
43 |
44 | This package supports usage of following extensions:
45 |
46 | - [yii2tech/ar-position](https://github.com/yii2tech/ar-position)
47 | - [yii2tech/ar-role](https://github.com/yii2tech/ar-role)
48 | - [yii2tech/ar-search](https://github.com/yii2tech/ar-search)
49 | - [yii2tech/ar-softdelete](https://github.com/yii2tech/ar-softdelete)
50 | - [yii2tech/ar-variation](https://github.com/yii2tech/ar-variation)
51 |
52 | > Note: none of these extensions is required by default, you'll need to install them yourself, if needed.
53 |
54 |
55 | ## Actions
56 |
57 | This extension provides several independent action classes, which provides particular operation support:
58 |
59 | - [[\yii2tech\admin\actions\Index]] - displays the models listing with search support.
60 | - [[\yii2tech\admin\actions\Create]] - supports creation of the new model using web form.
61 | - [[\yii2tech\admin\actions\Update]] - supports updating of the existing model using web form.
62 | - [[\yii2tech\admin\actions\Delete]] - performs the deleting of the existing record.
63 | - [[\yii2tech\admin\actions\View]] - displays an existing model.
64 | - [[\yii2tech\admin\actions\SoftDelete]] - performs the "soft" deleting of the existing record.
65 | - [[\yii2tech\admin\actions\SafeDelete]] - performs the "safe" deleting of the existing record.
66 | - [[\yii2tech\admin\actions\Restore]] - performs the restoration of the "soft" deleted record.
67 | - [[\yii2tech\admin\actions\Callback]] - allows invocation of specified method of the model.
68 | - [[\yii2tech\admin\actions\Position]] - allows change custom sort position of the particular model.
69 | - [[\yii2tech\admin\actions\VariationCreate]] - supports creation of the new model with variations using web form.
70 | - [[\yii2tech\admin\actions\VariationUpdate]] - supports updating of the new model with variations using web form.
71 | - [[\yii2tech\admin\actions\RoleCreate]] - supports creation of the new model with role using web form.
72 | - [[\yii2tech\admin\actions\RoleUpdate]] - supports updating of the new model with role using web form.
73 |
74 | Please refer to the particular action class for more details.
75 |
76 | For example CRUD controller based on provided actions may look like following:
77 |
78 | ```php
79 | namespace app\controllers;
80 |
81 | use yii\web\Controller;
82 |
83 | class ItemController extends Controller
84 | {
85 | public function actions()
86 | {
87 | return [
88 | 'index' => [
89 | 'class' => \yii2tech\admin\actions\Index::class,
90 | 'newSearchModel' => function () {
91 | return new ItemSearch();
92 | },
93 | ],
94 | 'view' => [
95 | 'class' => \yii2tech\admin\actions\View::class,
96 | ],
97 | 'create' => [
98 | 'class' => \yii2tech\admin\actions\Create::class,
99 | ],
100 | 'update' => [
101 | 'class' => \yii2tech\admin\actions\Update::class,
102 | ],
103 | 'delete' => [
104 | 'class' => \yii2tech\admin\actions\Delete::class,
105 | ],
106 | ];
107 | }
108 |
109 | public function findModel($id)
110 | {
111 | if (($model = Item::findOne($id)) !== null) {
112 | return $model;
113 | }
114 | throw new NotFoundHttpException('The requested page does not exist.');
115 | }
116 |
117 | public function newModel()
118 | {
119 | return new Item();
120 | }
121 | }
122 | ```
123 |
124 |
125 | ## Controllers
126 |
127 | This extension provides several predefined controllers, which can be used as a base controller classes
128 | while creating particular controllers:
129 |
130 | - [[\yii2tech\admin\CrudController]] - implements a common set of actions for supporting CRUD for ActiveRecord.
131 |
132 | Please refer to the particular controller class for more details.
133 |
134 |
135 | ## Widgets
136 |
137 | This extension provides several widgets, which simplifies view composition for the typical use cases:
138 |
139 | - [[\yii2tech\admin\widgets\Alert]] - renders a message from session flash.
140 | - [[\yii2tech\admin\widgets\ActionAlert]] - renders an action proposition based on particular condition, usually a session flag.
141 | - [[\yii2tech\admin\widgets\ButtonContextMenu]] - simplifies rendering of the context links such as 'update', 'view', 'delete' etc.
142 | - [[\yii2tech\admin\widgets\Nav]] - enhanced version of [[\yii\bootstrap\Nav]], which simplifies icon rendering.
143 |
144 | Also several enhancements for the [[\yii\grid\GridView]] are available:
145 |
146 | - [[\yii2tech\admin\grid\ActionColumn]] - simplifies composition of the action buttons
147 | - [[\yii2tech\admin\grid\DeleteStatusColumn]] - serves for the 'soft-deleted' status displaying
148 | - [[\yii2tech\admin\grid\PositionColumn]] - provides simple interface for the model custom sort position switching
149 | - [[\yii2tech\admin\grid\VariationColumn]] - allows displaying of the variation column values
150 |
151 |
152 | ## Using Gii
153 |
154 | This extension provides a code generators, which can be integrated with yii 'gii' module.
155 | In order to enable them, you should adjust your application configuration in following way:
156 |
157 | ```php
158 | return [
159 | //....
160 | 'modules' => [
161 | // ...
162 | 'gii' => [
163 | 'class' => yii\gii\Module::class,
164 | 'generators' => [
165 | 'adminMainFrame' => [
166 | 'class' => yii2tech\admin\gii\mainframe\Generator::class
167 | ],
168 | 'adminCrud' => [
169 | 'class' => yii2tech\admin\gii\crud\Generator::class
170 | ]
171 | ],
172 | ],
173 | ]
174 | ];
175 | ```
176 |
177 | "MainFrame" generator creates a basic admin panel code, which includes layout files, main controller
178 | file and basic view files. The created structure is necessary for the correct rendering of the code created
179 | by "Admin CRUD" generator.
180 |
181 | "Admin CRUD" generator is similar to regular "CRUD" generator, but it generates code, which uses tools from
182 | this extension, so the result code is much more clean.
183 |
184 |
185 | ## Internationalization
186 |
187 | All text and messages introduced in this extension are translatable under category 'yii2tech-admin'.
188 | You may use translations provided within this extension, using following application configuration:
189 |
190 | ```php
191 | return [
192 | 'components' => [
193 | 'i18n' => [
194 | 'translations' => [
195 | 'yii2tech-admin' => [
196 | 'class' => yii\i18n\PhpMessageSource::class,
197 | 'basePath' => '@yii2tech/admin/messages',
198 | ],
199 | // ...
200 | ],
201 | ],
202 | // ...
203 | ],
204 | // ...
205 | ];
206 | ```
207 |
--------------------------------------------------------------------------------
/UPGRADE.md:
--------------------------------------------------------------------------------
1 | Upgrading Instructions for Admin pack Extension for Yii 2
2 | =========================================================
3 |
4 | !!!IMPORTANT!!!
5 |
6 | The following upgrading instructions are cumulative. That is,
7 | if you want to upgrade from version A to version C and there is
8 | version B between A and C, you need to following the instructions
9 | for both A and B.
10 |
11 | Upgrade from 1.0.3
12 | ------------------
13 |
14 | * PHP requirements were raised to 5.6. Make sure your code is updated accordingly.
15 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yii2tech/admin",
3 | "description": "Admin pack (actions, widgets, etc) for Yii2",
4 | "keywords": ["yii2", "admin", "administration", "crud"],
5 | "type": "yii2-extension",
6 | "license": "BSD-3-Clause",
7 | "support": {
8 | "issues": "https://github.com/yii2tech/admin/issues",
9 | "forum": "http://www.yiiframework.com/forum/",
10 | "wiki": "https://github.com/yii2tech/admin/wiki",
11 | "source": "https://github.com/yii2tech/admin"
12 | },
13 | "authors": [
14 | {
15 | "name": "Paul Klimov",
16 | "email": "klimov.paul@gmail.com"
17 | }
18 | ],
19 | "require": {
20 | "php": ">=5.6.0",
21 | "yiisoft/yii2": "~2.0.14"
22 | },
23 | "require-dev": {
24 | "yiisoft/yii2-bootstrap": ">=2.0.5"
25 | },
26 | "suggest": {
27 | "yiisoft/yii2-bootstrap": "you need this package, if you wish to use provided widgets"
28 | },
29 | "repositories": [
30 | {
31 | "type": "composer",
32 | "url": "https://asset-packagist.org"
33 | }
34 | ],
35 | "autoload": {
36 | "psr-4": {"yii2tech\\admin\\": "src"}
37 | },
38 | "extra": {
39 | "branch-alias": {
40 | "dev-master": "1.0.x-dev"
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/ActionEvent.php:
--------------------------------------------------------------------------------
1 |
14 | * @since 1.0
15 | */
16 | class ActionEvent extends \yii\base\ActionEvent
17 | {
18 | /**
19 | * @var \yii\base\Model|null associated model instance.
20 | */
21 | public $model;
22 | }
--------------------------------------------------------------------------------
/src/CrudController.php:
--------------------------------------------------------------------------------
1 |
32 | * @since 1.0
33 | */
34 | class CrudController extends Controller
35 | {
36 | /**
37 | * @var string the model class name. This property must be set.
38 | * The model class must implement [[ActiveRecordInterface]].
39 | */
40 | public $modelClass;
41 | /**
42 | * @var string class name of the model which should be used as search model.
43 | * If not set it will be composed using [[modelClass]].
44 | */
45 | public $searchModelClass;
46 | /**
47 | * @var string the scenario used for updating a model.
48 | * @see Model::scenarios()
49 | */
50 | public $updateScenario = Model::SCENARIO_DEFAULT;
51 | /**
52 | * @var string the scenario used for creating a model.
53 | * @see Model::scenarios()
54 | */
55 | public $createScenario = Model::SCENARIO_DEFAULT;
56 |
57 |
58 | /**
59 | * {@inheritdoc}
60 | */
61 | public function behaviors()
62 | {
63 | return [
64 | 'model' => [
65 | 'class' => ModelControlBehavior::class,
66 | 'modelClass' => $this->modelClass,
67 | 'searchModelClass' => $this->searchModelClass,
68 | ],
69 | 'access' => [
70 | 'class' => AccessControl::class,
71 | 'rules' => $this->accessRules(),
72 | ],
73 | 'verbs' => [
74 | 'class' => VerbFilter::class,
75 | 'actions' => [
76 | 'delete' => ['post'],
77 | ],
78 | ],
79 | ];
80 | }
81 |
82 | /**
83 | * Returns the access rules for this controller.
84 | * This is method is a shortcut, allowing quick adjustment of the [[AccessControl]] filter attached at [[behaviors()]].
85 | * Be careful in case you override [[behaviors()]] method, since it may loose configuration provided by this method.
86 | * @return array list of access rules. See [[AccessControl::rules]] for details about rule specification.
87 | */
88 | public function accessRules()
89 | {
90 | return [
91 | [
92 | 'allow' => true,
93 | 'roles' => ['@'],
94 | ],
95 | ];
96 | }
97 |
98 | /**
99 | * {@inheritdoc}
100 | */
101 | public function actions()
102 | {
103 | return [
104 | 'index' => [
105 | 'class' => actions\Index::class,
106 | ],
107 | 'view' => [
108 | 'class' => actions\View::class,
109 | ],
110 | 'create' => [
111 | 'class' => actions\Create::class,
112 | 'scenario' => $this->createScenario,
113 | ],
114 | 'update' => [
115 | 'class' => actions\Update::class,
116 | 'scenario' => $this->updateScenario,
117 | ],
118 | 'delete' => [
119 | 'class' => actions\Delete::class,
120 | ],
121 | ];
122 | }
123 | }
--------------------------------------------------------------------------------
/src/actions/Action.php:
--------------------------------------------------------------------------------
1 |
22 | * @since 1.0
23 | */
24 | class Action extends \yii\base\Action
25 | {
26 | /**
27 | * @var callable a PHP callable that will be called to return the model corresponding
28 | * to the specified primary key value. If not set, [[findModel()]] will be used instead.
29 | * The signature of the callable should be:
30 | *
31 | * ```php
32 | * function ($id, $action) {
33 | * // $id is the primary key value. If composite primary key, the key values
34 | * // will be separated by comma.
35 | * // $action is the action object currently running
36 | * }
37 | * ```
38 | *
39 | * The callable should return the model found, or throw an exception if not found.
40 | */
41 | public $findModel;
42 | /**
43 | * @var string ID of the controller action, which user should be redirected to on success.
44 | * This property overrides the value set by [[setReturnAction()]] method.
45 | * @see getReturnAction()
46 | * @see returnUrl
47 | */
48 | public $returnAction;
49 | /**
50 | * @var string|array|callable URL, which user should be redirected to on success.
51 | * This could be a plain string URL, URL array configuration or callable, which returns actual URL.
52 | * The signature for the callable is following:
53 | *
54 | * ```
55 | * string|array function (Model $model) {}
56 | * ```
57 | *
58 | * Note: actual list of the callable arguments may vary depending on particular action class.
59 | *
60 | * Note: this option takes precedence over [[returnAction]] related logic.
61 | *
62 | * @see returnAction
63 | */
64 | public $returnUrl;
65 |
66 |
67 | /**
68 | * Returns the data model based on the primary key given.
69 | * If the data model is not found, a 404 HTTP exception will be raised.
70 | * @param string $id the ID of the model to be loaded. If the model has a composite primary key,
71 | * the ID must be a string of the primary key values separated by commas.
72 | * The order of the primary key values should follow that returned by the `primaryKey()` method
73 | * of the model.
74 | * @return ActiveRecordInterface|Model the model found
75 | * @throws NotFoundHttpException if the model cannot be found
76 | * @throws InvalidConfigException on invalid configuration
77 | */
78 | public function findModel($id)
79 | {
80 | if ($this->findModel !== null) {
81 | return call_user_func($this->findModel, $id, $this);
82 | } elseif ($this->controller->hasMethod('findModel')) {
83 | return call_user_func([$this->controller, 'findModel'], $id, $this);
84 | }
85 | throw new InvalidConfigException('Either "' . get_class($this) . '::$findModel" must be set or controller must declare method "findModel()".');
86 | }
87 |
88 | /**
89 | * Checks whether action with specified ID exists in owner controller.
90 | * @param string $id action ID.
91 | * @return boolean whether action exists or not.
92 | */
93 | public function actionExists($id)
94 | {
95 | $inlineActionMethodName = 'action' . Inflector::camelize($id);
96 | if (method_exists($this->controller, $inlineActionMethodName)) {
97 | return true;
98 | }
99 | if (array_key_exists($id, $this->controller->actions())) {
100 | return true;
101 | }
102 | return false;
103 | }
104 |
105 | /**
106 | * Sets the return action ID.
107 | * @param string|null $actionId action ID, if not set current action will be used.
108 | */
109 | public function setReturnAction($actionId = null)
110 | {
111 | if ($actionId === null) {
112 | $actionId = $this->id;
113 | }
114 | if (strpos($actionId, '/') === false) {
115 | $actionId = $this->controller->getUniqueId() . '/' . $actionId;
116 | }
117 | $sessionKey = '__adminReturnAction';
118 | Yii::$app->getSession()->set($sessionKey, $actionId);
119 | }
120 |
121 | /**
122 | * Returns the ID of action, which should be used for return redirect.
123 | * If action belongs to another controller or does not exist in current controller - 'index' is returned.
124 | * @param string $defaultActionId default action ID.
125 | * @return string action ID.
126 | */
127 | public function getReturnAction($defaultActionId = 'index')
128 | {
129 | if ($this->returnAction !== null) {
130 | return $this->returnAction;
131 | }
132 |
133 | $sessionKey = '__adminReturnAction';
134 | $actionId = Yii::$app->getSession()->get($sessionKey, $defaultActionId);
135 | $actionId = trim($actionId, '/');
136 | if ($actionId === 'index') {
137 | return $actionId;
138 | }
139 |
140 | if (strpos($actionId, '/') !== false) {
141 | $controllerId = StringHelper::dirname($actionId);
142 | if ($controllerId !== $this->controller->getUniqueId()) {
143 | return 'index';
144 | }
145 | $actionId = StringHelper::basename($actionId);
146 | }
147 |
148 | if (!$this->actionExists($actionId)) {
149 | return 'index';
150 | }
151 |
152 | return $actionId;
153 | }
154 |
155 | /**
156 | * @param string $defaultActionId default action ID.
157 | * @param ActiveRecordInterface|Model|null $model model being processed by action.
158 | * @return array|string URL
159 | */
160 | public function createReturnUrl($defaultActionId = 'index', $model = null)
161 | {
162 | if ($this->returnUrl !== null) {
163 | if (is_string($this->returnUrl)) {
164 | return $this->returnUrl;
165 | }
166 | if (!is_callable($this->returnUrl, true)) {
167 | return $this->returnUrl;
168 | }
169 |
170 | $args = func_get_args();
171 | array_shift($args);
172 | return call_user_func_array($this->returnUrl, $args);
173 | }
174 |
175 | $actionId = $this->getReturnAction($defaultActionId);
176 | $queryParams = Yii::$app->request->getQueryParams();
177 | unset($queryParams['id']);
178 | $url = array_merge(
179 | [$actionId],
180 | $queryParams
181 | );
182 | if (is_object($model) && in_array($actionId, ['view', 'update'], true)) {
183 | $url = array_merge(
184 | $url,
185 | ['id' => implode(',', array_values($model->getPrimaryKey(true)))]
186 | );
187 | }
188 | return $url;
189 | }
190 |
191 | /**
192 | * Sets a flash message.
193 | * @param string|array|null $message flash message(s) to be set.
194 | * If plain string is passed, it will be used as a message with the key 'success'.
195 | * You may specify multiple messages as an array, if element name is not integer, it will be used as a key,
196 | * otherwise 'success' will be used as key.
197 | * If empty value passed, no flash will be set.
198 | * Particular message value can be a PHP callback, which should return actual message. Such callback, should
199 | * have following signature:
200 | *
201 | * ```php
202 | * function (array $params) {
203 | * // return string
204 | * }
205 | * ```
206 | *
207 | * @param array $params extra params for the message parsing in format: key => value.
208 | */
209 | public function setFlash($message, $params = [])
210 | {
211 | if (empty($message)) {
212 | return;
213 | }
214 |
215 | $session = Yii::$app->session;
216 |
217 | foreach ((array)$message as $key => $value) {
218 | if (is_scalar($value)) {
219 | $value = preg_replace_callback("/{(\\w+)}/", function ($matches) use ($params) {
220 | $paramName = $matches[1];
221 | return isset($params[$paramName]) ? $params[$paramName] : $paramName;
222 | }, $value);
223 | } else {
224 | $value = call_user_func($value, $params);
225 | }
226 |
227 | if (is_int($key)) {
228 | $session->setFlash('success', $value);
229 | } else {
230 | $session->setFlash($key, $value);
231 | }
232 | }
233 | }
234 | }
--------------------------------------------------------------------------------
/src/actions/Callback.php:
--------------------------------------------------------------------------------
1 |
17 | * @since 1.0
18 | */
19 | class Callback extends Action
20 | {
21 | /**
22 | * @var string|callable name of the model method, which should be invoked
23 | * or callback, which should be executed for the found model.
24 | * The signature of the callable should be:
25 | *
26 | * ```php
27 | * function ($model) {
28 | * }
29 | * ```
30 | */
31 | public $callback;
32 | /**
33 | * @var string|array|null flash message to be set on success.
34 | * @see Action::setFlash() for details on how setup flash.
35 | */
36 | public $flash;
37 |
38 |
39 | /**
40 | * Invokes configured method on the specified model.
41 | * @param string $id the primary key of the model.
42 | * @return mixed response.
43 | * @throws InvalidConfigException on invalid configuration.
44 | */
45 | public function run($id)
46 | {
47 | $model = $this->findModel($id);
48 |
49 | if ($this->callback === null) {
50 | throw new InvalidConfigException('"' . get_class($this) . '::$callback" must be set.');
51 | }
52 | if (is_string($this->callback)) {
53 | call_user_func([$model, $this->callback]);
54 | } else {
55 | call_user_func($this->callback, $model);
56 | }
57 |
58 | $this->setFlash($this->flash, ['id' => $id, 'model' => $model]);
59 |
60 | return $this->controller->redirect($this->createReturnUrl('view', $model));
61 | }
62 | }
--------------------------------------------------------------------------------
/src/actions/Create.php:
--------------------------------------------------------------------------------
1 |
22 | * @since 1.0
23 | */
24 | class Create extends Action
25 | {
26 | use ModelFormTrait;
27 |
28 | /**
29 | * @var string name of the view, which should be rendered
30 | */
31 | public $view = 'create';
32 | /**
33 | * @var callable a PHP callable that will be called to create the new model.
34 | * If not set, [[newModel()]] will be used instead.
35 | * The signature of the callable should be:
36 | *
37 | * ```php
38 | * function ($action) {
39 | * // $action is the action object currently running
40 | * }
41 | * ```
42 | *
43 | * The callable should return the new model instance.
44 | */
45 | public $newModel;
46 | /**
47 | * @var boolean|callable provides control for model default values populating.
48 | * If set to `false` - no default value population will be performed.
49 | * If set to `true` - it will invoke `loadDefaultValues()` method on model.
50 | * You can set this as a callable of following signature:
51 | *
52 | * ```php
53 | * function ($model) {
54 | * // populate default values.
55 | * }
56 | * ```
57 | */
58 | public $loadDefaultValues = false;
59 |
60 |
61 | /**
62 | * Creates new model instance.
63 | * @return ActiveRecordInterface|Model new model instance.
64 | * @throws InvalidConfigException on invalid configuration.
65 | */
66 | public function newModel()
67 | {
68 | if ($this->newModel !== null) {
69 | return call_user_func($this->newModel, $this);
70 | } elseif ($this->controller->hasMethod('newModel')) {
71 | return call_user_func([$this->controller, 'newModel'], $this);
72 | }
73 | throw new InvalidConfigException('Either "' . get_class($this) . '::$newModel" must be set or controller must declare method "newModel()".');
74 | }
75 |
76 | /**
77 | * Creates new record.
78 | * @return mixed response
79 | */
80 | public function run()
81 | {
82 | $model = $this->newModel();
83 | $model->scenario = $this->scenario;
84 |
85 | if ($this->load($model, Yii::$app->request->post())) {
86 | if (Yii::$app->request->isAjax) {
87 | Yii::$app->response->format = Response::FORMAT_JSON;
88 | return $this->performAjaxValidation($model);
89 | }
90 | if ($model->save()) {
91 | $this->setFlash($this->flash, ['model' => $model]);
92 | return $this->controller->redirect($this->createReturnUrl('view', $model));
93 | }
94 | } else {
95 | $this->loadModelDefaultValues($model);
96 | }
97 |
98 | return $this->controller->render($this->view, [
99 | 'model' => $model,
100 | ]);
101 | }
102 |
103 | /**
104 | * Populates given model with the default values.
105 | * @param Model $model model to be processed.
106 | */
107 | protected function loadModelDefaultValues($model)
108 | {
109 | if ($this->loadDefaultValues === false) {
110 | return;
111 | }
112 | if ($this->loadDefaultValues === true) {
113 | $model->loadDefaultValues();
114 | } else {
115 | call_user_func($this->loadDefaultValues, $model);
116 | }
117 | }
118 | }
--------------------------------------------------------------------------------
/src/actions/Delete.php:
--------------------------------------------------------------------------------
1 |
16 | * @since 1.0
17 | */
18 | class Delete extends Action
19 | {
20 | /**
21 | * {@inheritdoc}
22 | */
23 | public $returnAction = 'index';
24 | /**
25 | * @var string|array|null flash message to be set on success.
26 | * @see Action::setFlash() for details on how setup flash.
27 | */
28 | public $flash;
29 |
30 |
31 | /**
32 | * Deletes a model.
33 | * @param mixed $id id of the model to be deleted.
34 | * @return mixed response.
35 | */
36 | public function run($id)
37 | {
38 | $model = $this->findModel($id);
39 |
40 | $model->delete();
41 |
42 | $this->setFlash($this->flash, ['id' => $id, 'model' => $model]);
43 |
44 | return $this->controller->redirect($this->createReturnUrl('index', $model));
45 | }
46 | }
--------------------------------------------------------------------------------
/src/actions/FlushCache.php:
--------------------------------------------------------------------------------
1 |
23 | * @since 1.0
24 | */
25 | class FlushCache extends Action
26 | {
27 | /**
28 | * @var array|Cache|string|null cache component(s), which should be flushed.
29 | * If not set action will flush all cache components found in current application.
30 | * Each cache component can be specified as application component name, instance of [[Cache]] or its configuration.
31 | * For example:
32 | *
33 | * ```php
34 | * [
35 | * 'cache',
36 | * 'frontendCache' => [
37 | * 'class' => \yii\caching\DbCache::class,
38 | * 'cacheTable' => '{{%frontendCache}}',
39 | * ],
40 | * 'objectCache' => new \yii\caching\DbCache(['cacheTable' => '{{%objectCache}}']),
41 | * ]
42 | * ```
43 | */
44 | public $cache;
45 | /**
46 | * @var string|array|null flash message to be set on success.
47 | * @see Action::setFlash() for details on how setup flash.
48 | */
49 | public $flash;
50 | /**
51 | * @var string|array the default return URL in case it was not set previously.
52 | * This URL will be used only in case automatic determine of return URL failed.
53 | */
54 | public $returnUrl;
55 |
56 |
57 | /**
58 | * Flushes associated cache components.
59 | * @param string|array|null $name name of the cache component(s), which should be flushed.
60 | * @return mixed response.
61 | */
62 | public function run($name = null)
63 | {
64 | $filter = (array)$name;
65 |
66 | if (empty($this->cache)) {
67 | $caches = $this->findCaches($filter);
68 | } else {
69 | $caches = (array)$this->cache;
70 |
71 | if (!empty($filter)) {
72 | foreach ($caches as $key => $value) {
73 | if (is_int($key)) {
74 | if (!in_array($value, $filter)) {
75 | unset($caches[$key]);
76 | }
77 | } else {
78 | if (!in_array($key, $filter)) {
79 | unset($caches[$key]);
80 | }
81 | }
82 | }
83 | }
84 | }
85 |
86 | $this->flushCaches($caches);
87 |
88 | $this->setFlash($this->flash);
89 |
90 | return $this->goBack();
91 | }
92 |
93 | /**
94 | * Returns array of caches in the system, keys are cache components names, values are class names.
95 | * @param array $cachesNames caches to be found
96 | * @return array
97 | */
98 | private function findCaches(array $cachesNames = [])
99 | {
100 | $caches = [];
101 | $components = Yii::$app->getComponents();
102 | $findAll = ($cachesNames === []);
103 |
104 | foreach ($components as $name => $component) {
105 | if (!$findAll && !in_array($name, $cachesNames)) {
106 | continue;
107 | }
108 |
109 | if ($component instanceof Cache) {
110 | $caches[] = $name;
111 | } elseif (is_array($component) && isset($component['class']) && $this->isCacheClass($component['class'])) {
112 | $caches[] = $name;
113 | } elseif (is_string($component) && $this->isCacheClass($component)) {
114 | $caches[] = $name;
115 | }
116 | }
117 |
118 | return $caches;
119 | }
120 |
121 | /**
122 | * Checks if given class is a Cache class.
123 | * @param string $className class name.
124 | * @return boolean
125 | */
126 | private function isCacheClass($className)
127 | {
128 | return is_subclass_of($className, Cache::class);
129 | }
130 |
131 | /**
132 | * Flushes given caches list.
133 | * @param array $caches caches list
134 | */
135 | private function flushCaches(array $caches)
136 | {
137 | foreach ($caches as $cache) {
138 | if (is_scalar($cache)) {
139 | Yii::$app->get($cache)->flush();
140 | } elseif ($cache instanceof Cache) {
141 | $cache->flush();
142 | } else {
143 | Yii::createObject($cache)->flush();
144 | }
145 | }
146 | }
147 |
148 | /**
149 | * Redirects the browser to the last visited page.
150 | * If such page can not be indicated [[returnUrl]] will be used.
151 | * @return mixed response.
152 | */
153 | private function goBack()
154 | {
155 | $referrerUrl = Yii::$app->getRequest()->getReferrer();
156 | if ($referrerUrl !== null) {
157 | return $this->controller->redirect($referrerUrl);
158 | }
159 | return $this->controller->goBack($this->returnUrl);
160 | }
161 | }
--------------------------------------------------------------------------------
/src/actions/Index.php:
--------------------------------------------------------------------------------
1 |
18 | * @since 1.0
19 | */
20 | class Index extends Action
21 | {
22 | /**
23 | * @var callable a PHP callable that will be called to create the new search model.
24 | * If not set, [[newSearchModel()]] will be used instead.
25 | * The signature of the callable should be:
26 | *
27 | * ```php
28 | * function ($action) {
29 | * // $action is the action object currently running
30 | * }
31 | * ```
32 | *
33 | * The callable should return the new model instance.
34 | */
35 | public $newSearchModel;
36 | /**
37 | * @var callable a PHP callable that will be called to prepare a data provider that
38 | * should return a collection of the models. If not set, [[prepareDataProvider()]] will be used instead.
39 | * The signature of the callable should be:
40 | *
41 | * ```php
42 | * function ($searchModel, $action) {
43 | * // $searchModel the search model instance
44 | * // $action is the action object currently running
45 | * }
46 | * ```
47 | *
48 | * The callable should return an instance of [[\yii\data\DataProviderInterface]].
49 | */
50 | public $prepareDataProvider;
51 | /**
52 | * @var string name of the view, which should be rendered
53 | */
54 | public $view = 'index';
55 |
56 |
57 | /**
58 | * Creates new search model instance.
59 | * @return Model new model instance.
60 | * @throws InvalidConfigException on invalid configuration.
61 | */
62 | public function newSearchModel()
63 | {
64 | if ($this->newSearchModel !== null) {
65 | return call_user_func($this->newSearchModel, $this);
66 | } elseif ($this->controller->hasMethod('newSearchModel')) {
67 | return call_user_func([$this->controller, 'newSearchModel'], $this);
68 | }
69 | throw new InvalidConfigException('Either "' . get_class($this) . '::$newSearchModel" must be set or controller must declare method "newSearchModel()".');
70 | }
71 |
72 | /**
73 | * Displays models list.
74 | * @return mixed response.
75 | */
76 | public function run()
77 | {
78 | $searchModel = $this->newSearchModel();
79 | $dataProvider = $this->prepareDataProvider($searchModel);
80 |
81 | $this->setReturnAction();
82 |
83 | return $this->controller->render($this->view, [
84 | 'searchModel' => $searchModel,
85 | 'dataProvider' => $dataProvider,
86 | ]);
87 | }
88 |
89 | /**
90 | * Prepares the data provider that should return the requested collection of the models.
91 | * @param Model $searchModel search model instance.
92 | * @return \yii\data\DataProviderInterface data provider instance.
93 | */
94 | protected function prepareDataProvider($searchModel)
95 | {
96 | if ($this->prepareDataProvider !== null) {
97 | return call_user_func($this->prepareDataProvider, $searchModel, $this);
98 | }
99 |
100 | return $searchModel->search(Yii::$app->request->queryParams);
101 | }
102 | }
--------------------------------------------------------------------------------
/src/actions/ModelFormTrait.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | trait ModelFormTrait
22 | {
23 | /**
24 | * @var string the scenario to be assigned to the new model before it is validated and saved.
25 | */
26 | public $scenario = Model::SCENARIO_DEFAULT;
27 | /**
28 | * @var string|array|null flash message to be set on success.
29 | * @see Action::setFlash() for details on how setup flash.
30 | */
31 | public $flash;
32 |
33 |
34 | /**
35 | * Populates the model with input data.
36 | * @param Model $model model instance.
37 | * @param array $data the data array to load, typically `$_POST` or `$_GET`.
38 | * @return boolean whether expected forms are found in `$data`.
39 | */
40 | protected function load($model, $data)
41 | {
42 | /* @var $this Action */
43 | $event = new ActionEvent($this, [
44 | 'model' => $model,
45 | 'result' => $model->load($data),
46 | ]);
47 | $this->trigger('afterDataLoad', $event);
48 |
49 | return $event->result;
50 | }
51 |
52 | /**
53 | * Performs AJAX validation of the model via [[ActiveForm::validate()]].
54 | * @param Model $model main model.
55 | * @return array the error message array indexed by the attribute IDs.
56 | */
57 | protected function performAjaxValidation($model)
58 | {
59 | /* @var $this Action */
60 | $event = new ActionEvent($this, [
61 | 'model' => $model,
62 | 'result' => ActiveForm::validate($model),
63 | ]);
64 |
65 | $this->trigger('afterAjaxValidate', $event);
66 |
67 | return $event->result;
68 | }
69 | }
--------------------------------------------------------------------------------
/src/actions/Position.php:
--------------------------------------------------------------------------------
1 |
21 | * @since 1.0
22 | */
23 | class Position extends Action
24 | {
25 | /**
26 | * @var string name of the query param, which is used for new model position specification.
27 | */
28 | public $positionParam = 'at';
29 |
30 |
31 | /**
32 | * Updates existing record specified by id.
33 | * @param mixed $id id of the model to be deleted.
34 | * @return mixed response.
35 | * @throws BadRequestHttpException on invalid request.
36 | */
37 | public function run($id)
38 | {
39 | $position = Yii::$app->request->getQueryParam($this->positionParam, null);
40 | if (empty($position)) {
41 | throw new BadRequestHttpException(Yii::t('yii', '{attribute} cannot be blank.', ['attribute' => $this->positionParam]));
42 | }
43 |
44 | $model = $this->findModel($id);
45 |
46 | $this->positionModel($model, $position);
47 |
48 | return $this->respondSuccess($model);
49 | }
50 |
51 | /**
52 | * @param \yii\db\ActiveRecordInterface|\yii2tech\ar\position\PositionBehavior $model
53 | * @param $position
54 | * @throws BadRequestHttpException
55 | */
56 | protected function positionModel($model, $position)
57 | {
58 | switch (strtolower($position)) {
59 | case 'up':
60 | case 'prev':
61 | $model->movePrev();
62 | break;
63 | case 'down':
64 | case 'next':
65 | $model->moveNext();
66 | break;
67 | case 'top':
68 | case 'first':
69 | $model->moveFirst();
70 | break;
71 | case 'bottom':
72 | case 'last':
73 | $model->moveLast();
74 | break;
75 | default:
76 | if (is_numeric($position)) {
77 | $model->moveToPosition($position);
78 | } else {
79 | throw new BadRequestHttpException(Yii::t('yii', '{attribute} is invalid.', ['attribute' => $this->positionParam]));
80 | }
81 | }
82 | }
83 |
84 | /**
85 | * Composes success response.
86 | * @param \yii\db\ActiveRecordInterface $model
87 | * @return mixed response.
88 | */
89 | protected function respondSuccess($model)
90 | {
91 | if (Yii::$app->request->isAjax) {
92 | Yii::$app->response->format = Response::FORMAT_JSON;
93 | return [
94 | 'success' => true
95 | ];
96 | }
97 |
98 | return $this->controller->redirect($this->createReturnUrl('view', $model));
99 | }
100 |
101 | /**
102 | * {@inheritdoc}
103 | */
104 | public function createReturnUrl($defaultActionId = 'index', $model = null)
105 | {
106 | if ($this->returnUrl !== null) {
107 | return parent::createReturnUrl($defaultActionId, $model);
108 | }
109 |
110 | $url = parent::createReturnUrl($defaultActionId, $model);
111 | unset($url[$this->positionParam]);
112 | return $url;
113 | }
114 | }
--------------------------------------------------------------------------------
/src/actions/Restore.php:
--------------------------------------------------------------------------------
1 |
18 | * @since 1.0
19 | */
20 | class Restore extends Action
21 | {
22 | /**
23 | * @var string|array|null flash message to be set on success.
24 | * @see Action::setFlash() for details on how setup flash.
25 | */
26 | public $flash;
27 |
28 |
29 | /**
30 | * Deletes a model.
31 | * @param mixed $id id of the model to be deleted.
32 | * @return mixed response.
33 | */
34 | public function run($id)
35 | {
36 | $model = $this->findModel($id);
37 |
38 | $model->restore();
39 |
40 | $this->setFlash($this->flash, ['id' => $id, 'model' => $model]);
41 |
42 | return $this->controller->redirect($this->createReturnUrl('view', $model));
43 | }
44 | }
--------------------------------------------------------------------------------
/src/actions/RoleCreate.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | class RoleCreate extends Create
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function behaviors()
27 | {
28 | return [
29 | [
30 | 'class' => RoleBehavior::class
31 | ]
32 | ];
33 | }
34 | }
--------------------------------------------------------------------------------
/src/actions/RoleUpdate.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | class RoleUpdate extends Update
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function behaviors()
27 | {
28 | return [
29 | [
30 | 'class' => RoleBehavior::class
31 | ]
32 | ];
33 | }
34 | }
--------------------------------------------------------------------------------
/src/actions/SafeDelete.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | class SafeDelete extends Delete
22 | {
23 | /**
24 | * Deletes a model.
25 | * @param mixed $id id of the model to be deleted.
26 | * @return mixed response.
27 | */
28 | public function run($id)
29 | {
30 | $model = $this->findModel($id);
31 |
32 | $model->safeDelete();
33 |
34 | $this->setFlash($this->flash, ['id' => $id, 'model' => $model]);
35 |
36 | return $this->controller->redirect($this->createReturnUrl('index', $model));
37 | }
38 | }
--------------------------------------------------------------------------------
/src/actions/SoftDelete.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | class SoftDelete extends Delete
22 | {
23 | /**
24 | * Deletes a model.
25 | * @param mixed $id id of the model to be deleted.
26 | * @return mixed response.
27 | */
28 | public function run($id)
29 | {
30 | $model = $this->findModel($id);
31 |
32 | $model->softDelete();
33 |
34 | $this->setFlash($this->flash, ['id' => $id, 'model' => $model]);
35 |
36 | return $this->controller->redirect($this->createReturnUrl('index', $model));
37 | }
38 | }
--------------------------------------------------------------------------------
/src/actions/Update.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | class Update extends Action
22 | {
23 | use ModelFormTrait;
24 |
25 | /**
26 | * @var string name of the view, which should be rendered
27 | */
28 | public $view = 'update';
29 |
30 |
31 | /**
32 | * Updates existing record specified by id.
33 | * @param mixed $id id of the model to be deleted.
34 | * @return mixed response.
35 | */
36 | public function run($id)
37 | {
38 | $model = $this->findModel($id);
39 | $model->scenario = $this->scenario;
40 |
41 | if ($this->load($model, Yii::$app->request->post())) {
42 | if (Yii::$app->request->isAjax) {
43 | Yii::$app->response->format = Response::FORMAT_JSON;
44 | return $this->performAjaxValidation($model);
45 | }
46 | if ($model->save()) {
47 | $this->setFlash($this->flash, ['id' => $id, 'model' => $model]);
48 | return $this->controller->redirect($this->createReturnUrl('view', $model));
49 | }
50 | }
51 |
52 | return $this->controller->render($this->view, [
53 | 'model' => $model,
54 | ]);
55 | }
56 | }
--------------------------------------------------------------------------------
/src/actions/VariationCreate.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | class VariationCreate extends Create
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function behaviors()
27 | {
28 | return [
29 | [
30 | 'class' => VariationBehavior::class
31 | ]
32 | ];
33 | }
34 | }
--------------------------------------------------------------------------------
/src/actions/VariationUpdate.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | class VariationUpdate extends Update
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function behaviors()
27 | {
28 | return [
29 | [
30 | 'class' => VariationBehavior::class
31 | ]
32 | ];
33 | }
34 | }
--------------------------------------------------------------------------------
/src/actions/View.php:
--------------------------------------------------------------------------------
1 |
14 | * @since 1.0
15 | */
16 | class View extends Action
17 | {
18 | /**
19 | * @var string name of the view, which should be rendered
20 | */
21 | public $view = 'view';
22 |
23 |
24 | /**
25 | * Displays a model.
26 | * @param string $id the primary key of the model.
27 | * @return mixed response.
28 | */
29 | public function run($id)
30 | {
31 | $model = $this->findModel($id);
32 |
33 | $this->setReturnAction();
34 |
35 | return $this->controller->render($this->view, [
36 | 'model' => $model,
37 | ]);
38 | }
39 | }
--------------------------------------------------------------------------------
/src/behaviors/ContextModelControlBehavior.php:
--------------------------------------------------------------------------------
1 |
32 | * @since 1.0
33 | */
34 | class ContextModelControlBehavior extends ModelControlBehavior
35 | {
36 | /**
37 | * @var array specifies possible contexts.
38 | * The array key is considered as context name, value - as context config.
39 | * Config should contain following keys:
40 | *
41 | * - class: string, class name of context model.
42 | * - attribute: string, name of model attribute, which refers to the context model primary key.
43 | * - url: array|string, URL config or route to the controller, which manage context models.
44 | * - required: boolean, whether this context is mandatory for this controller or optional.
45 | *
46 | * For example:
47 | *
48 | * ```php
49 | * [
50 | * 'user' => [
51 | * 'class' => User::class,
52 | * 'attribute' => 'userId',
53 | * 'url' => 'user/view',
54 | * ]
55 | * ]
56 | * ```
57 | */
58 | public $contexts;
59 |
60 | /**
61 | * @var ActiveRecordInterface[]|Model[] stores the active context models, which means the ones, which passed
62 | * through the query params.
63 | */
64 | private $_contextModels;
65 |
66 |
67 | /**
68 | * Return context info by given name.
69 | * If 'null' name provided the first declared context will be returned.
70 | * @param string|null $name context name.
71 | * @return array context config.
72 | */
73 | public function getContext($name = null)
74 | {
75 | if ($name === null) {
76 | reset($this->contexts);
77 | return current($this->contexts);
78 | }
79 | if (!isset($this->contexts[$name])) {
80 | throw new InvalidArgumentException("Undefined context '{$name}'");
81 | }
82 |
83 | return $this->contexts[$name];
84 | }
85 |
86 | /**
87 | * @return ActiveRecordInterface[]|Model[] active context models
88 | */
89 | public function getContextModels()
90 | {
91 | if (!is_array($this->_contextModels)) {
92 | $this->_contextModels = $this->findContextModels();
93 | }
94 | return $this->_contextModels;
95 | }
96 |
97 | /**
98 | * @param ActiveRecordInterface[]|Model[] $contextModels active context models
99 | */
100 | public function setContextModels($contextModels)
101 | {
102 | $this->_contextModels = $contextModels;
103 | }
104 |
105 | /**
106 | * Return active context model by given name.
107 | * If 'null' name provided the first active context model will be returned.
108 | * @param string|null $name context name.
109 | * @return ActiveRecordInterface|Model default active context model.
110 | */
111 | public function getContextModel($name = null)
112 | {
113 | $contextModels = $this->getContextModels();
114 | if ($name === null) {
115 | if (empty($contextModels)) {
116 | throw new InvalidArgumentException("There is no context model.");
117 | }
118 | reset($contextModels);
119 | return current($contextModels);
120 | }
121 | if (!isset($contextModels[$name])) {
122 | throw new InvalidArgumentException("Undefined context '{$name}'");
123 | }
124 |
125 | return $contextModels[$name];
126 | }
127 |
128 | /**
129 | * Finds all active context models.
130 | * @return ActiveRecordInterface[]|Model[] active contexts.
131 | * @throws InvalidConfigException on invalid configuration.
132 | * @throws NotFoundHttpException on missing required context.
133 | */
134 | protected function findContextModels()
135 | {
136 | $contextModels = [];
137 | if (is_array($this->contexts)) {
138 | $queryParams = Yii::$app->request->getQueryParams();
139 | foreach ($this->contexts as $name => $config) {
140 | if (empty($config['attribute'])) {
141 | throw new InvalidConfigException('Context "attribute" parameter must be set.');
142 | }
143 | $attribute = $config['attribute'];
144 | if (array_key_exists($attribute, $queryParams)) {
145 | $contextModels[$name] = $this->findContextModel($config, $queryParams[$attribute]);
146 | } elseif (isset($config['required']) && $config['required']) {
147 | throw new NotFoundHttpException(Yii::t('yii2tech-admin', "Context '{name}' required.", ['name' => $name]));
148 | }
149 | }
150 | }
151 | return $contextModels;
152 | }
153 |
154 | /**
155 | * Initializes a particular active context.
156 | * @param array $config context configuration.
157 | * @param mixed $id context model primary key value.
158 | * @return ActiveRecordInterface|Model context model instance.
159 | * @throws InvalidConfigException on invalid configuration.
160 | * @throws NotFoundHttpException if context model not found.
161 | */
162 | protected function findContextModel($config, $id)
163 | {
164 | if (empty($config['class'])) {
165 | throw new InvalidConfigException('Context "class" parameter must be set.');
166 | }
167 |
168 | /* @var $modelClass ActiveRecordInterface */
169 | $modelClass = $config['class'];
170 | $keys = $modelClass::primaryKey();
171 | if (count($keys) > 1) {
172 | $values = explode(',', $id);
173 | if (count($keys) === count($values)) {
174 | $model = $modelClass::findOne(array_combine($keys, $values));
175 | }
176 | } elseif ($id !== null) {
177 | $model = $modelClass::findOne($id);
178 | }
179 |
180 | if (isset($model)) {
181 | return $model;
182 | }
183 | throw new NotFoundHttpException(Yii::t('yii2tech-admin', "Context object not found: {id}", ['id' => $id]));
184 | }
185 |
186 | /**
187 | * Checks if named context is active (present in the query params).
188 | * If 'null' name provided, checks if at least one context is active.
189 | * @param string|null $name context name.
190 | * @return boolean whether context is active.
191 | */
192 | public function isContextActive($name = null)
193 | {
194 | $contextModels = $this->getContextModels();
195 | if ($name === null) {
196 | return (!empty($contextModels));
197 | }
198 | return isset($contextModels[$name]);
199 | }
200 |
201 | // URL :
202 |
203 | /**
204 | * Returns query params for currently active contexts, like `['groupId' => 12]`.
205 | * This method can be used to compose links.
206 | * @return array query params.
207 | */
208 | public function getContextQueryParams()
209 | {
210 | $queryParams = [];
211 | foreach ($this->getContextModels() as $name => $model) {
212 | $queryParams[$this->contexts[$name]['attribute']] = $model->getPrimaryKey();
213 | }
214 | return $queryParams;
215 | }
216 |
217 | /**
218 | * Composes URL, which leads to the context model index page.
219 | * @param string|null $name context name.
220 | * @return array URL config.
221 | */
222 | public function getContextUrl($name = null)
223 | {
224 | $config = $this->getContext($name);
225 |
226 | if (isset($config['indexUrl'])) {
227 | $url = (array)$config['indexUrl'];
228 | } else {
229 | if (isset($config['controller'])) {
230 | $controllerId = $config['controller'];
231 | } else {
232 | if ($name !== null) {
233 | $controllerId = $name;
234 | } else {
235 | $controllerId = trim(substr($config['attribute'], 0, -2), '_');
236 | }
237 | }
238 | $url = ["/{$controllerId}/index"];
239 | }
240 |
241 | return $url;
242 | }
243 |
244 | /**
245 | * Composes URL, which leads to the context model details page.
246 | * @param string|null $name context name.
247 | * @return array URL config.
248 | */
249 | public function getContextModelUrl($name = null)
250 | {
251 | $model = $this->getContextModel($name);
252 | $config = $this->getContext($name);
253 |
254 | if (isset($config['viewUrl'])) {
255 | $url = (array)$config['viewUrl'];
256 | } else {
257 | if (isset($config['controller'])) {
258 | $controllerId = $config['controller'];
259 | } else {
260 | if ($name !== null) {
261 | $controllerId = $name;
262 | } else {
263 | $controllerId = Inflector::camel2id(StringHelper::basename(get_class($model)));
264 | }
265 | }
266 | $url = ["/{$controllerId}/view"];
267 | }
268 |
269 | $url['id'] = $model->getPrimaryKey();
270 | return $url;
271 | }
272 |
273 | // Override :
274 |
275 | /**
276 | * {@inheritdoc}
277 | */
278 | public function findModel($id)
279 | {
280 | $model = parent::findModel($id);
281 | foreach ($this->getContextModels() as $name => $contextModel) {
282 | $attribute = $this->contexts[$name]['attribute'];
283 | if ($model->$attribute != $contextModel->getPrimaryKey()) {
284 | throw new NotFoundHttpException(Yii::t('yii2tech-admin', "Object not found: {id}", ['id' => $contextModel->getPrimaryKey()]));
285 | }
286 | }
287 | return $model;
288 | }
289 |
290 | /**
291 | * {@inheritdoc}
292 | */
293 | public function newModel()
294 | {
295 | $model = parent::newModel();
296 | foreach ($this->getContextModels() as $name => $contextModel) {
297 | $attribute = $this->contexts[$name]['attribute'];
298 | $model->$attribute = $contextModel->getPrimaryKey();
299 | }
300 | return $model;
301 | }
302 |
303 | /**
304 | * {@inheritdoc}
305 | */
306 | public function newSearchModel()
307 | {
308 | $model = parent::newSearchModel();
309 | foreach ($this->getContextModels() as $name => $contextModel) {
310 | $attribute = $this->contexts[$name]['attribute'];
311 | $model->$attribute = $contextModel->getPrimaryKey();
312 | }
313 | return $model;
314 | }
315 | }
--------------------------------------------------------------------------------
/src/behaviors/ModelControlBehavior.php:
--------------------------------------------------------------------------------
1 |
24 | * @since 1.0
25 | */
26 | class ModelControlBehavior extends Behavior
27 | {
28 | /**
29 | * @var string the model class name. This property must be set.
30 | * The model class must implement [[ActiveRecordInterface]].
31 | * @see newModel()
32 | * @see findModel()
33 | */
34 | public $modelClass;
35 | /**
36 | * @var string|callable class name of the model which should be used as search model.
37 | * This can be a PHP callback of following signature:
38 | *
39 | * ```php
40 | * function (\yii\web\Controller $controller) {
41 | * //return new \yii\base\Model;
42 | * }
43 | * ```
44 | *
45 | * If not set it will be composed using [[modelClass]].
46 | * If [yii2tech/ar-search](https://github.com/yii2tech/ar-search) extension is installed -
47 | * [[\yii2tech\ar\search\ActiveSearchModel]] instance will be used as a search model.
48 | *
49 | * @see newSearchModel()
50 | */
51 | public $searchModelClass;
52 |
53 |
54 | /**
55 | * Returns the data model based on the primary key given.
56 | * If the data model is not found, a 404 HTTP exception will be raised.
57 | * @param string $id the ID of the model to be loaded. If the model has a composite primary key,
58 | * the ID must be a string of the primary key values separated by commas.
59 | * The order of the primary key values should follow that returned by the `primaryKey()` method
60 | * of the model.
61 | * @return ActiveRecordInterface|Model the model found
62 | * @throws NotFoundHttpException if the model cannot be found
63 | * @throws InvalidConfigException on invalid configuration
64 | */
65 | public function findModel($id)
66 | {
67 | if ($this->modelClass === null) {
68 | throw new InvalidConfigException('"' . get_class($this) . '::$modelClass" must be set.');
69 | }
70 |
71 | /* @var $modelClass ActiveRecordInterface */
72 | $modelClass = $this->modelClass;
73 | $keys = $modelClass::primaryKey();
74 | if (count($keys) > 1) {
75 | $values = explode(',', $id);
76 | if (count($keys) === count($values)) {
77 | $model = $modelClass::findOne(array_combine($keys, $values));
78 | }
79 | } elseif ($id !== null) {
80 | $model = $modelClass::findOne($id);
81 | }
82 |
83 | if (isset($model)) {
84 | return $model;
85 | }
86 | throw new NotFoundHttpException(Yii::t('yii2tech-admin', "Object not found: {id}", ['id' => $id]));
87 | }
88 |
89 | /**
90 | * Creates new model instance.
91 | * @return ActiveRecordInterface|Model new model instance.
92 | * @throws InvalidConfigException on invalid configuration.
93 | */
94 | public function newModel()
95 | {
96 | if ($this->modelClass === null) {
97 | throw new InvalidConfigException('"' . get_class($this) . '::$modelClass" must be set.');
98 | }
99 | $modelClass = $this->modelClass;
100 | return new $modelClass();
101 | }
102 |
103 | /**
104 | * Creates new search model instance.
105 | * @return Model new search model instance.
106 | * @throws InvalidConfigException on invalid configuration.
107 | */
108 | public function newSearchModel()
109 | {
110 | $modelClass = $this->searchModelClass;
111 | if ($modelClass === null) {
112 | if ($this->modelClass === null) {
113 | throw new InvalidConfigException('Either "' . get_class($this) . '::$searchModelClass" or "' . get_class($this) . '::$modelClass" must be set.');
114 | }
115 |
116 | if (class_exists('yii2tech\ar\search\ActiveSearchModel')) {
117 | $searchModel = new \yii2tech\ar\search\ActiveSearchModel();
118 | $searchModel->setModel($this->modelClass);
119 | return $searchModel;
120 | }
121 |
122 | $modelClass = $this->modelClass . 'Search';
123 | } elseif (!is_string($modelClass)) {
124 | return call_user_func($modelClass, $this->owner);
125 | }
126 |
127 | return new $modelClass();
128 | }
129 | }
--------------------------------------------------------------------------------
/src/behaviors/action/RoleBehavior.php:
--------------------------------------------------------------------------------
1 |
26 | * @since 1.0
27 | */
28 | class RoleBehavior extends Behavior
29 | {
30 | /**
31 | * @var array list of model role behavior names, which should be affected by the action.
32 | * If empty - all instances of [[RoleBehavior]] will be picked up.
33 | */
34 | public $roleNames = [];
35 |
36 | /**
37 | * @var array cache for the role models.
38 | */
39 | private $_roleModels = [];
40 |
41 |
42 | /**
43 | * Get role models for the main one.
44 | * @param Model|ActiveRecordInterface $model main model instance.
45 | * @return Model[] list of role models
46 | */
47 | public function getRoleModels($model)
48 | {
49 | $key = serialize($model->getPrimaryKey());
50 | if (!isset($this->_roleModels[$key])) {
51 | $this->_roleModels[$key] = $this->findRoleModels($model);
52 | }
53 | return $this->_roleModels[$key];
54 | }
55 |
56 | /**
57 | * @param Model|ActiveRecordInterface $model
58 | * @return array list of variation models in format: behaviorName => Model[]
59 | */
60 | private function findRoleModels($model)
61 | {
62 | $roleModels = [];
63 | foreach ($model->getBehaviors() as $name => $behavior) {
64 | if ((empty($this->roleNames) && ($behavior instanceof \yii2tech\ar\role\RoleBehavior)) || in_array($name, $this->roleNames)) {
65 | $roleModels[$name] = $behavior->getRoleRelationModel();
66 | }
67 | }
68 | return $roleModels;
69 | }
70 |
71 | // Events :
72 |
73 | /**
74 | * {@inheritdoc}
75 | */
76 | public function events()
77 | {
78 | return [
79 | 'afterDataLoad' => 'afterDataLoad',
80 | 'afterAjaxValidate' => 'afterAjaxValidate',
81 | ];
82 | }
83 |
84 | /**
85 | * Handles `afterDataLoad` event.
86 | * Populates the role models with input data.
87 | * @param ActionEvent $event event instance.
88 | */
89 | public function afterDataLoad($event)
90 | {
91 | if (!$event->result) {
92 | return;
93 | }
94 |
95 | $model = $event->model;
96 | $data = Yii::$app->request->post();
97 |
98 | foreach ($this->getRoleModels($model) as $roleModel) {
99 | if (!$roleModel->load($data)) {
100 | return;
101 | }
102 | }
103 | }
104 |
105 | /**
106 | * Performs AJAX validation of the role models via [[ActiveForm::validate()]].
107 | * @param ActionEvent $event event instance.
108 | */
109 | public function afterAjaxValidate($event)
110 | {
111 | $model = $event->model;
112 |
113 | $roleModels = $this->getRoleModels($model);
114 |
115 | $event->result = array_merge(
116 | $event->result,
117 | call_user_func_array([ActiveForm::class, 'validate'], $roleModels)
118 | );
119 | }
120 | }
--------------------------------------------------------------------------------
/src/behaviors/action/VariationBehavior.php:
--------------------------------------------------------------------------------
1 |
26 | * @since 1.0
27 | */
28 | class VariationBehavior extends Behavior
29 | {
30 | /**
31 | * @var array list of model variation behavior names, which should be affected by the action.
32 | * If empty - all instances of [[\yii2tech\ar\variation\VariationBehavior]] will be picked up.
33 | */
34 | public $variationNames = [];
35 |
36 | /**
37 | * @var array cache for the variation model batches.
38 | */
39 | private $_variationModelBatches = [];
40 |
41 |
42 | /**
43 | * Get variation models for the main one in batches.
44 | * @param Model|ActiveRecordInterface $model main model instance.
45 | * @return array list of variation models in format: behaviorName => Model[]
46 | */
47 | protected function getVariationModelBatches($model)
48 | {
49 | $key = serialize($model->getPrimaryKey());
50 | if (!isset($this->_variationModelBatches[$key])) {
51 | $this->_variationModelBatches[$key] = $this->findVariationModelBatches($model);
52 | }
53 | return $this->_variationModelBatches[$key];
54 | }
55 |
56 | /**
57 | * @param Model|ActiveRecordInterface $model
58 | * @return array list of variation models in format: behaviorName => Model[]
59 | */
60 | protected function findVariationModelBatches($model)
61 | {
62 | $variationModels = [];
63 | foreach ($model->getBehaviors() as $name => $behavior) {
64 | if ((empty($this->variationNames) && ($behavior instanceof \yii2tech\ar\variation\VariationBehavior)) || in_array($name, $this->variationNames)) {
65 | $variationModels[$name] = $behavior->getVariationModels();
66 | }
67 | }
68 | return $variationModels;
69 | }
70 |
71 | // Events :
72 |
73 | /**
74 | * {@inheritdoc}
75 | */
76 | public function events()
77 | {
78 | return [
79 | 'afterDataLoad' => 'afterDataLoad',
80 | 'afterAjaxValidate' => 'afterAjaxValidate',
81 | ];
82 | }
83 |
84 | /**
85 | * Handles `afterDataLoad` event.
86 | * Populates the variation models with input data.
87 | * @param ActionEvent $event event instance.
88 | */
89 | public function afterDataLoad($event)
90 | {
91 | if (!$event->result) {
92 | return;
93 | }
94 |
95 | $model = $event->model;
96 | $data = Yii::$app->request->post();
97 |
98 | foreach ($this->getVariationModelBatches($model) as $variationName => $variationModels) {
99 | if (empty($variationModels)) {
100 | continue;
101 | }
102 | if (!Model::loadMultiple($variationModels, $data)) {
103 | $event->result = false;
104 | }
105 | }
106 | }
107 |
108 | /**
109 | * Handles `afterAjaxValidate` event.
110 | * Performs AJAX validation of the variation models via [[ActiveForm::validate()]].
111 | * @param ActionEvent $event event instance.
112 | */
113 | protected function afterAjaxValidate($event)
114 | {
115 | $model = $event->model;
116 | $response = $event->result;
117 |
118 | // validate variations manually for tabular input matching :
119 | foreach ($this->getVariationModelBatches($model) as $variationModels) {
120 | foreach ($variationModels as $index => $variationModel) {
121 | /* @var $variationModel Model */
122 | if (!$variationModel->validate()) {
123 | foreach ($model->getErrors() as $attribute => $errors) {
124 | $response[Html::getInputId($model, '[' . $index . ']' . $attribute)] = $errors;
125 | }
126 | }
127 | }
128 | }
129 |
130 | $event->data['result'] = $response;
131 | }
132 | }
--------------------------------------------------------------------------------
/src/gii/crud/Generator.php:
--------------------------------------------------------------------------------
1 |
18 | * @since 1.0
19 | */
20 | class Generator extends \yii\gii\generators\crud\Generator
21 | {
22 | /**
23 | * @var string controller context model classes.
24 | */
25 | public $contextClass;
26 | /**
27 | * {@inheritdoc}
28 | */
29 | public $baseControllerClass = 'yii2tech\admin\CrudController';
30 | /**
31 | * {@inheritdoc}
32 | */
33 | public $messageCategory = 'admin';
34 |
35 |
36 | /**
37 | * {@inheritdoc}
38 | */
39 | public function getName()
40 | {
41 | return 'Admin CRUD Generator';
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | public function getDescription()
48 | {
49 | return 'This generator generates a controller and views that implement CRUD (Create, Read, Update, Delete)
50 | operations for the specified data model.';
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function rules()
57 | {
58 | return array_merge(parent::rules(), [
59 | ['contextClass', 'safe'],
60 | ['contextClass', 'match', 'pattern' => '/^[\w\\\\]+(\s*,\s*[\w\\\\]+)*$/', 'message' => 'Only word characters and backslashes are allowed.'],
61 | ]);
62 | }
63 |
64 | /**
65 | * {@inheritdoc}
66 | */
67 | public function attributeLabels()
68 | {
69 | return array_merge(parent::attributeLabels(), [
70 | 'contextClass' => 'Context Class',
71 | ]);
72 | }
73 |
74 | /**
75 | * {@inheritdoc}
76 | */
77 | public function hints()
78 | {
79 | return array_merge(parent::hints(), [
80 | 'contextClass' => 'This is the ActiveRecord class, which serves as context for the contoller.
81 | You should provide a fully qualified class name, e.g., app\models\User
.
82 | You may specify several classes separated by comma.',
83 | ]);
84 | }
85 |
86 | /**
87 | * {@inheritdoc}
88 | */
89 | public function stickyAttributes()
90 | {
91 | return array_merge(parent::stickyAttributes(), ['contextClass']);
92 | }
93 |
94 | /**
95 | * Returns the root path to the original parent default code template files.
96 | * @return string the root path to the original parent default code template files.
97 | */
98 | public function parentDefaultTemplate()
99 | {
100 | return Yii::getAlias('@yii/gii/generators/crud/default');
101 | }
102 |
103 | /**
104 | * {@inheritdoc}
105 | */
106 | public function getNameAttribute()
107 | {
108 | foreach ($this->getColumnNames() as $name) {
109 | if (!strcasecmp($name, 'username') || !strcasecmp($name, 'email')) {
110 | return $name;
111 | }
112 | }
113 | return parent::getNameAttribute();
114 | }
115 |
116 | /**
117 | * @return array contexts in format: contextName => contextClassName.
118 | */
119 | public function getContexts()
120 | {
121 | if (empty($this->contextClass)) {
122 | return [];
123 | }
124 | $result = [];
125 | $classes = preg_split('/,/', $this->contextClass, -1, PREG_SPLIT_NO_EMPTY);
126 | foreach ($classes as $class) {
127 | $result[Inflector::camel2id(StringHelper::basename($class))] = $class;
128 | }
129 | return $result;
130 | }
131 | }
--------------------------------------------------------------------------------
/src/gii/crud/default/controller.php:
--------------------------------------------------------------------------------
1 | controllerClass);
12 | $contexts = $generator->getContexts();
13 |
14 | echo "
16 |
17 | namespace = StringHelper::dirname(ltrim($generator->controllerClass, '\\')) ?>;
18 |
19 | use = ltrim($generator->baseControllerClass, '\\') ?>;
20 |
21 | use yii\helpers\ArrayHelper;
22 | use yii2tech\admin\behaviors\ContextModelControlBehavior;
23 |
24 |
25 | /**
26 | * = $controllerClass ?> implements the CRUD actions for [[= $generator->modelClass ?>]] model.
27 | * @see \= $generator->modelClass . "\n" ?>
28 | */
29 | class = $controllerClass ?> extends = StringHelper::basename($generator->baseControllerClass) . "\n" ?>
30 | {
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public $modelClass = \= $generator->modelClass ?>::class;
35 | searchModelClass)): ?>
36 | /**
37 | * {@inheritdoc}
38 | */
39 | public $searchModelClass = \= $generator->searchModelClass ?>::class;
40 |
41 |
42 | /**
43 | * Contexts configuration
44 | * @see ContextModelControlBehavior::$contexts
45 | */
46 | public $contexts = [
47 | $class) : ?>
48 | // Specify actual contexts :
49 | '= $name ?>' => [
50 | 'class' => \= $class ?>::class,
51 | 'attribute' => '= lcfirst(StringHelper::basename($class)) ?>Id',
52 | 'controller' => '= $name ?>',
53 | 'required' => false,
54 | ],
55 | ];
56 |
57 |
58 |
59 | /**
60 | * {@inheritdoc}
61 | */
62 | public function behaviors()
63 | {
64 | return ArrayHelper::merge(
65 | parent::behaviors(),
66 | [
67 | 'model' => [
68 | 'class' => ContextModelControlBehavior::class,
69 | 'contexts' => $this->contexts
70 | ]
71 | ]
72 | );
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/gii/crud/default/search.php:
--------------------------------------------------------------------------------
1 | parentDefaultTemplate() . DIRECTORY_SEPARATOR . 'search.php';
--------------------------------------------------------------------------------
/src/gii/crud/default/views/_form.php:
--------------------------------------------------------------------------------
1 | modelClass();
8 | $safeAttributes = $model->safeAttributes();
9 | if (empty($safeAttributes)) {
10 | $safeAttributes = $model->attributes();
11 | }
12 |
13 | echo "
15 | /**
16 | * @see \= $generator->controllerClass . "\n" ?>
17 | controllerClass, 'yii2tech\admin\CrudController')): ?>
18 | * @see \yii2tech\admin\actions\Create
19 | * @see \yii2tech\admin\actions\Update
20 |
21 | */
22 |
23 | use yii\bootstrap\Html;
24 | use yii\bootstrap\ActiveForm;
25 |
26 | /* @var $this yii\web\View */
27 | /* @var $model = ltrim($generator->modelClass, '\\') ?> */
28 | /* @var $form yii\widgets\ActiveForm */
29 | ?>
30 |
31 |
32 |
33 |
34 | = "$form = ActiveForm::begin(); ?>
35 |
36 | getColumnNames() as $attribute) {
37 | if (in_array($attribute, $safeAttributes)) {
38 | echo " = " . $generator->generateActiveField($attribute) . " ?>\n\n";
39 | }
40 | } ?>
41 |
42 | = "= " ?>Html::submitButton($model->isNewRecord ? = $generator->generateString('Create') ?> : = $generator->generateString('Update') ?>, ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
43 |
44 |
45 | = "ActiveForm::end(); ?>
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/gii/crud/default/views/_search.php:
--------------------------------------------------------------------------------
1 | parentDefaultTemplate() . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . '_search.php';
7 |
--------------------------------------------------------------------------------
/src/gii/crud/default/views/create.php:
--------------------------------------------------------------------------------
1 | getContexts();
10 |
11 | echo "
13 | /**
14 | * @see \= $generator->controllerClass . "\n" ?>
15 | controllerClass, 'yii2tech\admin\CrudController')): ?>
16 | * @see \yii2tech\admin\actions\Create
17 |
18 | */
19 |
20 | /* @var $this yii\web\View */
21 | /* @var $model = ltrim($generator->modelClass, '\\') ?> */
22 |
23 | /* @var $controller = $generator->controllerClass ?>|yii2tech\admin\behaviors\ContextModelControlBehavior */
24 |
25 | $controller = $this->context;
26 | $contextUrlParams = $controller->getContextQueryParams();
27 |
28 |
29 | $this->title = = $generator->generateString('Create ' . Inflector::camel2words(StringHelper::basename($generator->modelClass))) ?>;
30 |
31 | foreach ($controller->getContextModels() as $name => $contextModel) {
32 | $this->params['breadcrumbs'][] = ['label' => $name, 'url' => $controller->getContextUrl($name)];
33 | $this->params['breadcrumbs'][] = ['label' => $contextModel->id, 'url' => $controller->getContextModelUrl($name)];
34 | }
35 | $this->params['breadcrumbs'][] = ['label' => = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => array_merge(['index'], $contextUrlParams)];
36 |
37 | $this->params['breadcrumbs'][] = ['label' => = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']];
38 |
39 | $this->params['breadcrumbs'][] = $this->title;
40 | ?>
41 |
42 | = "= " ?>$this->render('_form', [
43 | 'model' => $model,
44 | ]) ?>
45 |
--------------------------------------------------------------------------------
/src/gii/crud/default/views/index.php:
--------------------------------------------------------------------------------
1 | generateUrlParams();
10 | $nameAttribute = $generator->getNameAttribute();
11 | $contexts = $generator->getContexts();
12 |
13 | echo "
15 | /**
16 | * @see \= $generator->controllerClass . "\n" ?>
17 | controllerClass, yii2tech\admin\CrudController::class)): ?>
18 | * @see \yii2tech\admin\actions\Index
19 |
20 | */
21 |
22 | indexWidgetType === 'grid'): ?>
23 | use yii\grid\GridView;
24 | use yii2tech\admin\grid\ActionColumn;
25 |
26 | use yii\widgets\ListView;
27 |
28 |
29 | /* @var $this yii\web\View */
30 | /* @var $searchModel = !empty($generator->searchModelClass) ? ltrim($generator->searchModelClass, '\\') : 'yii\base\Model' ?> */
31 | /* @var $dataProvider yii\data\ActiveDataProvider */
32 |
33 | /* @var $controller = $generator->controllerClass ?>|yii2tech\admin\behaviors\ContextModelControlBehavior */
34 |
35 | $controller = $this->context;
36 | $contextUrlParams = $controller->getContextQueryParams();
37 |
38 |
39 | $this->title = = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>;
40 |
41 | foreach ($controller->getContextModels() as $name => $contextModel) {
42 | $this->params['breadcrumbs'][] = ['label' => $name, 'url' => $controller->getContextUrl($name)];
43 | $this->params['breadcrumbs'][] = ['label' => $contextModel->id, 'url' => $controller->getContextModelUrl($name)];
44 | }
45 |
46 | $this->params['breadcrumbs'][] = $this->title;
47 |
48 | $this->params['contextMenuItems'] = [
49 | array_merge(['create'], $contextUrlParams)
50 | ];
51 |
52 | $this->params['contextMenuItems'] = [
53 | ['create']
54 | ];
55 |
56 | ?>
57 | searchModelClass) && $generator->indexWidgetType !== 'grid'): ?>
58 | = "\n echo $this->render('_search', ['model' => $searchModel]); ?>
59 |
60 |
61 | indexWidgetType === 'grid'): ?>
62 | = "= " ?>GridView::widget([
63 | 'dataProvider' => $dataProvider,
64 | = !empty($generator->searchModelClass) ? "'filterModel' => \$searchModel,\n 'columns' => [\n" : "'columns' => [\n"; ?>
65 | ['class' => \yii\grid\SerialColumn::class],
66 |
67 | getTableSchema()) === false) {
70 | foreach ($generator->getColumnNames() as $name) {
71 | if (++$count < 6) {
72 | echo " '" . $name . "',\n";
73 | } else {
74 | echo " // '" . $name . "',\n";
75 | }
76 | }
77 | } else {
78 | foreach ($tableSchema->columns as $column) {
79 | $format = $generator->generateColumnFormat($column);
80 | if (++$count < 6) {
81 | echo " '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
82 | } else {
83 | echo " // '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
84 | }
85 | }
86 | }
87 | ?>
88 |
89 | [
90 | 'class' => ActionColumn::class,
91 | ],
92 | ],
93 | ]); ?>
94 |
95 | = "= " ?>ListView::widget([
96 | 'dataProvider' => $dataProvider,
97 | 'itemOptions' => ['class' => 'item'],
98 | 'itemView' => function ($model, $key, $index, $widget) {
99 | return Html::a(Html::encode($model->= $nameAttribute ?>), array_merge(['view', = $urlParams ?>], $contextUrlParams));
100 | },
101 | ]) ?>
102 |
103 |
--------------------------------------------------------------------------------
/src/gii/crud/default/views/update.php:
--------------------------------------------------------------------------------
1 | generateUrlParams();
10 | $contexts = $generator->getContexts();
11 |
12 | echo "
14 | /**
15 | * @see \= $generator->controllerClass . "\n" ?>
16 | controllerClass, 'yii2tech\admin\CrudController')): ?>
17 | * @see \yii2tech\admin\actions\Update
18 |
19 | */
20 |
21 | /* @var $this yii\web\View */
22 | /* @var $model = ltrim($generator->modelClass, '\\') ?> */
23 |
24 | /* @var $controller = $generator->controllerClass ?>|yii2tech\admin\behaviors\ContextModelControlBehavior */
25 |
26 | $controller = $this->context;
27 | $contextUrlParams = $controller->getContextQueryParams();
28 |
29 |
30 | $this->title = = $generator->generateString('Update ' . Inflector::camel2words(StringHelper::basename($generator->modelClass)) . ': ') ?> . $model->= $generator->getNameAttribute() ?>;
31 |
32 | foreach ($controller->getContextModels() as $name => $contextModel) {
33 | $this->params['breadcrumbs'][] = ['label' => $name, 'url' => $controller->getContextUrl($name)];
34 | $this->params['breadcrumbs'][] = ['label' => $contextModel->id, 'url' => $controller->getContextModelUrl($name)];
35 | }
36 | $this->params['breadcrumbs'][] = ['label' => = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => array_merge(['index'], $contextUrlParams)];
37 | $this->params['breadcrumbs'][] = ['label' => $model->= $generator->getNameAttribute() ?>, 'url' => array_merge(['view', = $urlParams ?>], $contextUrlParams)];
38 |
39 | $this->params['breadcrumbs'][] = ['label' => = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']];
40 | $this->params['breadcrumbs'][] = ['label' => $model->= $generator->getNameAttribute() ?>, 'url' => ['view', = $urlParams ?>]];
41 |
42 | $this->params['breadcrumbs'][] = = $generator->generateString('Update') ?>;
43 | ?>
44 |
45 | = "= " ?>$this->render('_form', [
46 | 'model' => $model,
47 | ]) ?>
48 |
--------------------------------------------------------------------------------
/src/gii/crud/default/views/view.php:
--------------------------------------------------------------------------------
1 | generateUrlParams();
10 | $contexts = $generator->getContexts();
11 |
12 | echo "
14 | /**
15 | * @see \= $generator->controllerClass . "\n" ?>
16 | controllerClass, 'yii2tech\admin\CrudController')): ?>
17 | * @see \yii2tech\admin\actions\View
18 |
19 | */
20 |
21 | use yii\bootstrap\Html;
22 | use yii\widgets\DetailView;
23 |
24 | /* @var $this yii\web\View */
25 | /* @var $model = ltrim($generator->modelClass, '\\') ?> */
26 |
27 | /* @var $controller = $generator->controllerClass ?>|yii2tech\admin\behaviors\ContextModelControlBehavior */
28 |
29 | $controller = $this->context;
30 | $contextUrlParams = $controller->getContextQueryParams();
31 |
32 |
33 | $this->title = $model->= $generator->getNameAttribute() ?>;
34 |
35 | foreach ($controller->getContextModels() as $name => $contextModel) {
36 | $this->params['breadcrumbs'][] = ['label' => $name, 'url' => $controller->getContextUrl($name)];
37 | $this->params['breadcrumbs'][] = ['label' => $contextModel->id, 'url' => $controller->getContextModelUrl($name)];
38 | }
39 | $this->params['breadcrumbs'][] = ['label' => = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => array_merge(['index'], $contextUrlParams)];
40 |
41 | $this->params['breadcrumbs'][] = ['label' => = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']];
42 |
43 | $this->params['breadcrumbs'][] = $this->title;
44 |
45 | $this->params['contextMenuItems'] = [
46 | array_merge(['update', = $urlParams ?>], $contextUrlParams),
47 | array_merge(['delete', = $urlParams ?>], $contextUrlParams)
48 | ];
49 |
50 | $this->params['contextMenuItems'] = [
51 | ['update', = $urlParams ?>],
52 | ['delete', = $urlParams ?>]
53 | ];
54 |
55 | ?>
56 |
57 |
58 | = "= " ?>DetailView::widget([
59 | 'model' => $model,
60 | 'attributes' => [
61 | getTableSchema()) === false) {
63 | foreach ($generator->getColumnNames() as $name) {
64 | echo " '" . $name . "',\n";
65 | }
66 | } else {
67 | foreach ($generator->getTableSchema()->columns as $column) {
68 | $format = $generator->generateColumnFormat($column);
69 | echo " '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
70 | }
71 | }
72 | ?>
73 | ],
74 | ]) ?>
75 |
76 |
--------------------------------------------------------------------------------
/src/gii/crud/form.php:
--------------------------------------------------------------------------------
1 | field($generator, 'modelClass');
7 | echo $form->field($generator, 'searchModelClass');
8 | echo $form->field($generator, 'controllerClass');
9 | echo $form->field($generator, 'viewPath');
10 | echo $form->field($generator, 'contextClass');
11 | echo $form->field($generator, 'baseControllerClass');
12 | echo $form->field($generator, 'indexWidgetType')->dropDownList([
13 | 'grid' => 'GridView',
14 | 'list' => 'ListView',
15 | ]);
16 | echo $form->field($generator, 'enableI18N')->checkbox();
17 | echo $form->field($generator, 'messageCategory');
18 |
--------------------------------------------------------------------------------
/src/gii/mainframe/Generator.php:
--------------------------------------------------------------------------------
1 |
20 | * @since 1.0
21 | */
22 | class Generator extends \yii\gii\Generator
23 | {
24 | /**
25 | * @var string main controller class name
26 | */
27 | public $controllerClass = 'app\controllers\admin\SiteController';
28 | /**
29 | * @var string base controller class
30 | */
31 | public $baseControllerClass = 'yii\web\Controller';
32 | /**
33 | * @var string view path
34 | */
35 | public $viewPath = '@app/views/admin';
36 | /**
37 | * @var string login form model class
38 | */
39 | public $loginModelClass = 'app\models\admin\LoginForm';
40 | /**
41 | * {@inheritdoc}
42 | */
43 | public $messageCategory = 'admin';
44 |
45 |
46 | /**
47 | * {@inheritdoc}
48 | */
49 | public function getName()
50 | {
51 | return 'Admin MainFrame Generator';
52 | }
53 |
54 | /**
55 | * {@inheritdoc}
56 | */
57 | public function getDescription()
58 | {
59 | return 'This generator generates layouts and common views for administration area. Created layouts supports correct
60 | rendering of the admin CRUD views';
61 | }
62 |
63 | /**
64 | * {@inheritdoc}
65 | */
66 | public function generate()
67 | {
68 | $controllerFile = Yii::getAlias('@' . str_replace('\\', '/', ltrim($this->controllerClass, '\\')) . '.php');
69 |
70 | // Controller :
71 | $files = [
72 | new CodeFile($controllerFile, $this->render('controller.php')),
73 | ];
74 |
75 | // Layouts :
76 | $viewPath = $this->getViewPath() . '/layouts';
77 | $templatePath = $this->getTemplatePath() . '/layouts';
78 | foreach (scandir($templatePath) as $file) {
79 | if (is_file($templatePath . '/' . $file) && pathinfo($file, PATHINFO_EXTENSION) === 'php') {
80 | $files[] = new CodeFile("$viewPath/$file", $this->render("layouts/$file"));
81 | }
82 | }
83 |
84 | // Controller views :
85 | $viewPath = $this->getViewPath() . '/' . $this->getControllerID();
86 | $templatePath = $this->getTemplatePath() . '/views';
87 | foreach (scandir($templatePath) as $file) {
88 | if (is_file($templatePath . '/' . $file) && pathinfo($file, PATHINFO_EXTENSION) === 'php') {
89 | $files[] = new CodeFile("$viewPath/$file", $this->render("views/$file"));
90 | }
91 | }
92 |
93 | return $files;
94 | }
95 |
96 | /**
97 | * {@inheritdoc}
98 | */
99 | public function rules()
100 | {
101 | return array_merge(parent::rules(), [
102 | [['loginModelClass', 'controllerClass', 'viewPath'], 'filter', 'filter' => 'trim'],
103 | [['loginModelClass', 'controllerClass', 'viewPath'], 'required'],
104 | [['loginModelClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'],
105 | [['loginModelClass'], 'validateClass', 'params' => ['extends' => Model::class]],
106 | [['baseControllerClass'], 'validateClass', 'params' => ['extends' => Controller::class]],
107 | [['controllerClass'], 'match', 'pattern' => '/Controller$/', 'message' => 'Controller class name must be suffixed with "Controller".'],
108 | [['controllerClass'], 'match', 'pattern' => '/(^|\\\\)[A-Z][^\\\\]+Controller$/', 'message' => 'Controller class name must start with an uppercase letter.'],
109 | [['controllerClass'], 'validateNewClass'],
110 | [['viewPath'], 'match', 'pattern' => '/^@?\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'],
111 | [['viewPath'], 'validatePath'],
112 | [['enableI18N'], 'boolean'],
113 | [['messageCategory'], 'validateMessageCategory', 'skipOnEmpty' => false],
114 | ]);
115 | }
116 |
117 | /**
118 | * {@inheritdoc}
119 | */
120 | public function attributeLabels()
121 | {
122 | return array_merge(parent::attributeLabels(), [
123 | 'loginModelClass' => 'Login Model Class',
124 | 'controllerClass' => 'Controller Class',
125 | 'viewPath' => 'View Path',
126 | 'baseControllerClass' => 'Base Controller Class',
127 | ]);
128 | }
129 |
130 | /**
131 | * {@inheritdoc}
132 | */
133 | public function requiredTemplates()
134 | {
135 | return ['controller.php'];
136 | }
137 |
138 | /**
139 | * {@inheritdoc}
140 | */
141 | public function hints()
142 | {
143 | return array_merge(parent::hints(), [
144 | 'loginModelClass' => 'This is the model class for admin panel login form. You should provide a fully qualified class name, e.g., app\models\admin\LoginForm
.',
145 | 'controllerClass' => 'This is the name of the controller class to be generated. You should
146 | provide a fully qualified namespaced class (e.g. app\controllers\admin\SiteController
),
147 | and class name should be in CamelCase with an uppercase first letter. Make sure the class
148 | is using the same namespace as specified by your application\'s controllerNamespace property.',
149 | 'viewPath' => 'This is the root view path to keep the generated view files. You may provide either a directory or a path alias, e.g., @app/views/admin
.',
150 | 'baseControllerClass' => 'This is the class that the new CRUD controller class will extend from.
151 | You should provide a fully qualified class name, e.g., yii\web\Controller
.',
152 | ]);
153 | }
154 |
155 | /**
156 | * {@inheritdoc}
157 | */
158 | public function stickyAttributes()
159 | {
160 | return array_merge(parent::stickyAttributes(), ['baseControllerClass']);
161 | }
162 |
163 | /**
164 | * Validates file path to make sure it is a valid path or path alias and exists.
165 | * @param string $attribute the attribute currently being validated.
166 | * @param array $params the additional name-value pairs given in the rule.
167 | */
168 | public function validatePath($attribute, $params)
169 | {
170 | $path = Yii::getAlias($this->{$attribute}, false);
171 | if ($path === false || !is_dir($path)) {
172 | $this->addError($attribute, 'Path does not exist.');
173 | }
174 | }
175 |
176 | /**
177 | * @return string the controller ID (without the module ID prefix)
178 | */
179 | public function getControllerID()
180 | {
181 | $pos = strrpos($this->controllerClass, '\\');
182 | $class = substr(substr($this->controllerClass, $pos + 1), 0, -10);
183 |
184 | return Inflector::camel2id($class);
185 | }
186 |
187 | /**
188 | * @return string the controller view path
189 | */
190 | public function getViewPath()
191 | {
192 | return Yii::getAlias($this->viewPath);
193 | }
194 | }
--------------------------------------------------------------------------------
/src/gii/mainframe/default/controller.php:
--------------------------------------------------------------------------------
1 | controllerClass);
12 | $loginModelClass = StringHelper::basename($generator->loginModelClass);
13 |
14 | echo "
16 |
17 | namespace = StringHelper::dirname(ltrim($generator->controllerClass, '\\')) ?>;
18 |
19 | use Yii;
20 | use yii\filters\AccessControl;
21 | use yii\filters\VerbFilter;
22 | use = ltrim($generator->baseControllerClass, '\\') ?>;
23 | use = ltrim($generator->loginModelClass, '\\') ?>;
24 |
25 | /**
26 | * = $controllerClass ?> implements the common actions for admin panel.
27 | */
28 | class = $controllerClass ?> extends = StringHelper::basename($generator->baseControllerClass) . "\n" ?>
29 | {
30 | /**
31 | * {@inheritdoc}
32 | */
33 | public function behaviors()
34 | {
35 | return [
36 | 'access' => [
37 | 'class' => AccessControl::class,
38 | 'rules' => [
39 | [
40 | 'actions' => ['login', 'error'],
41 | 'allow' => true,
42 | ],
43 | [
44 | 'actions' => ['logout', 'index'],
45 | 'allow' => true,
46 | 'roles' => ['@'],
47 | ],
48 | ],
49 | ],
50 | 'verbs' => [
51 | 'class' => VerbFilter::class,
52 | 'actions' => [
53 | 'logout' => ['post'],
54 | ],
55 | ],
56 | ];
57 | }
58 |
59 | /**
60 | * {@inheritdoc}
61 | */
62 | public function actions()
63 | {
64 | return [
65 | 'error' => [
66 | 'class' => \yii\web\ErrorAction::class,
67 | ],
68 | ];
69 | }
70 |
71 | /**
72 | * Renders dashborad.
73 | * @return mixed response.
74 | */
75 | public function actionIndex()
76 | {
77 | return $this->render('index');
78 | }
79 |
80 | /**
81 | * Renders login form.
82 | * @return mixed response.
83 | */
84 | public function actionLogin()
85 | {
86 | if (!Yii::$app->user->isGuest) {
87 | return $this->goHome();
88 | }
89 |
90 | $model = new = $loginModelClass ?>();
91 | if ($model->load(Yii::$app->request->post()) && $model->login()) {
92 | return $this->goBack();
93 | }
94 |
95 | return $this->render('login', [
96 | 'model' => $model,
97 | ]);
98 | }
99 |
100 | /**
101 | * Logs out user.
102 | * @return mixed response.
103 | */
104 | public function actionLogout()
105 | {
106 | Yii::$app->user->logout();
107 |
108 | return $this->goHome();
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/gii/mainframe/default/layouts/main.php:
--------------------------------------------------------------------------------
1 |
11 |
12 | use yii\bootstrap\Html;
13 | use yii2tech\admin\widgets\ButtonContextMenu;
14 |
15 | /* @var $this \yii\web\View */
16 | /* @var $content string */
17 | = "?>" ?>
18 | = " $this->beginContent($this->findViewFile('/layouts/overall')); ?>
19 | str_replace('/', '-', $this->context->action->getUniqueId()) ?>">
20 |
= "= " ?> Html::encode(isset($this->params['header']) ? $this->params['header'] : $this->title) ?>
21 |
22 |
23 | = "= " ?> ButtonContextMenu::widget([
24 | 'items' => isset($this->params['contextMenuItems']) ? $this->params['contextMenuItems'] : []
25 | ]) ?>
26 |
27 |
28 | = "= " ?> $content ?>
29 |
30 | = " $this->endContent(); ?>
--------------------------------------------------------------------------------
/src/gii/mainframe/default/layouts/mainMenu.php:
--------------------------------------------------------------------------------
1 |
11 |
12 | use yii2tech\admin\widgets\Nav;
13 | use yii\bootstrap\NavBar;
14 |
15 | /* @var $this \yii\web\View */
16 |
17 | $webUser = Yii::$app->user;
18 |
19 | NavBar::begin([
20 | 'id' => 'header-nav-bar',
21 | 'brandLabel' => Yii::$app->name,
22 | 'brandUrl' => Yii::$app->homeUrl,
23 | 'options' => [
24 | 'class' => 'navbar-inverse navbar-fixed-top',
25 | ],
26 | 'innerContainerOptions' => [
27 | 'class' => 'container-fluid'
28 | ],
29 | ]);
30 |
31 | if (!$webUser->isGuest) {
32 | echo Nav::widget([
33 | 'id' => 'header-main-menu',
34 | 'options' => ['class' => 'navbar-nav'],
35 | 'items' => [
36 | [
37 | 'label' => = $generator->generateString('Users') ?>,
38 | 'icon' => 'user',
39 | 'items' => [
40 | [
41 | 'label' => = $generator->generateString('Administrators') ?>,
42 | 'icon' => 'user',
43 | 'url' => ['admin/index'],
44 | ],
45 | [
46 | 'label' => = $generator->generateString('Users') ?>,
47 | 'icon' => 'user',
48 | 'url' => ['user/index'],
49 | ],
50 | ],
51 | ],
52 | ],
53 | ]);
54 | }
55 |
56 | $menuItems = [
57 | ['label' => Yii::t('yii', 'Home'), 'url' => Yii::$app->request->getBaseUrl() . '/', 'icon' => 'home'],
58 | ];
59 | if ($webUser->isGuest) {
60 | $menuItems[] = ['label' => = $generator->generateString('Login') ?>, 'url' => ['/site/login'], 'icon' => 'log-in'];
61 | } else {
62 | $menuItems[] = [
63 | 'label' => $webUser->identity->username,
64 | 'items' => [
65 | [
66 | 'label' => = $generator->generateString('Profile') ?>,
67 | 'url' => ['/admin/update', 'id' => $webUser->id],
68 | 'icon' => 'pencil'
69 | ],
70 | [
71 | 'label' => = $generator->generateString('Logout') ?>,
72 | 'url' => ['/site/logout'],
73 | 'linkOptions' => ['data-method' => 'post'],
74 | 'icon' => 'log-out',
75 | ],
76 | ],
77 |
78 | ];
79 | }
80 | echo Nav::widget([
81 | 'id' => 'header-common-menu',
82 | 'options' => ['class' => 'navbar-nav navbar-right'],
83 | 'items' => $menuItems,
84 | ]);
85 | NavBar::end();
--------------------------------------------------------------------------------
/src/gii/mainframe/default/layouts/overall.php:
--------------------------------------------------------------------------------
1 |
11 |
12 | use app\assets\admin\AppAsset;
13 | use yii\helpers\Html;
14 | use yii\widgets\Breadcrumbs;
15 | use yii2tech\admin\widgets\Alert;
16 |
17 | /* @var $this \yii\web\View */
18 | /* @var $content string */
19 |
20 | AppAsset::register($this);
21 | ?>
22 | = " $this->beginPage() ?>
23 |
24 | Yii::$app->language ?>">
25 |
26 | Yii::$app->charset ?>">
27 |
28 | = "= " ?> Html::csrfMetaTags() ?>
29 | = "= " ?> Html::encode($this->title) ?>
30 | = " $this->head() ?>
31 |
32 |
33 | = " $this->beginBody() ?>
34 |
35 |
36 | = "= " ?> $this->render('/layouts/mainMenu'); ?>
37 |
38 |
39 | = " if (!Yii::$app->user->isGuest) : ?>
40 | = "= " ?> Breadcrumbs::widget([
41 | 'homeLink' => [
42 | 'label' => Yii::t('admin', 'Administration'),
43 | 'url' => Yii::$app->homeUrl,
44 | ],
45 | 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
46 | ]) ?>
47 | = "= " ?> Alert::widget() ?>
48 | = " endif; ?>
49 | = "= " ?> $content ?>
50 |
51 |
52 |
53 |
58 |
59 | = " $this->endBody() ?>
60 |
61 |
62 | = " $this->endPage() ?>
63 |
--------------------------------------------------------------------------------
/src/gii/mainframe/default/views/error.php:
--------------------------------------------------------------------------------
1 |
11 |
12 | /* @var $this yii\web\View */
13 | /* @var $name string */
14 | /* @var $message string */
15 | /* @var $exception Exception */
16 |
17 | use yii\helpers\Html;
18 |
19 | $this->title = $name;
20 | ?>
21 |
22 |
23 | = "= " ?> nl2br(Html::encode($message)) ?>
24 |
25 |
26 |
27 | = $generator->generateString('The above error occurred while the Web server was processing your request.') ?>
28 |
--------------------------------------------------------------------------------
/src/gii/mainframe/default/views/index.php:
--------------------------------------------------------------------------------
1 |
11 |
12 | use yii\bootstrap\Html;
13 |
14 | /* @var $this yii\web\View */
15 |
16 | $this->title = = $generator->generateString('{appName} Administration', ['appName' => Yii::$app->name]) ?>;
17 |
18 | $blocks = [
19 | [
20 | 'title' => 'Administrator Accounts',
21 | 'description' => 'Setup administrator accounts',
22 | 'label' => 'Administrators',
23 | 'icon' => 'user',
24 | 'url' => ['/administrator/index'],
25 | ],
26 | [
27 | 'title' => 'Users Accounts',
28 | 'description' => 'Manage users accounts',
29 | 'label' => 'Users',
30 | 'icon' => 'user',
31 | 'url' => ['/user/index'],
32 | ],
33 | ];
34 | ?>
35 |
36 |
37 |
38 | = " foreach ($blocks as $number => $block): ?>
39 | = " if ($number % 3 == 0): ?>
40 | = " if ($number != 0): ?>
41 |
42 | = " endif; ?>
43 |
44 | = " endif; ?>
45 |
46 |
= "= " ?> $block['title'] ?>
47 |
= "= " ?> $block['description'] ?>
48 |
= "= " ?> Html::a(Html::icon($block['icon']) . ' ' . $block['label'], $block['url'], ['class' => 'btn btn-default']) ?>
49 |
50 | = " endforeach; ?>
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/gii/mainframe/default/views/login.php:
--------------------------------------------------------------------------------
1 |
11 |
12 | /* @var $this yii\web\View */
13 | /* @var $form yii\bootstrap\ActiveForm */
14 | /* @var $model = $generator->loginModelClass ?> */
15 |
16 | use yii\bootstrap\Html;
17 | use yii\bootstrap\ActiveForm;
18 |
19 | $this->title = = $generator->generateString('Login') ?>;
20 | $this->params['breadcrumbs'][] = $this->title;
21 | ?>
22 |
23 |
24 | = " $form = ActiveForm::begin(['id' => 'login-form']); ?>
25 |
26 | = "= " ?> $form->field($model, 'username') ?>
27 |
28 | = "= " ?> $form->field($model, 'password')->passwordInput() ?>
29 |
30 | = " if (Yii::$app->user->enableAutoLogin) : ?>
31 | = "= " ?> $form->field($model, 'rememberMe')->checkbox() ?>
32 | = " endif; ?>
33 |
34 |
35 | = "= " ?> Html::submitButton(= $generator->generateString('Login') ?>, ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
36 |
37 |
38 | = " ActiveForm::end(); ?>
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/gii/mainframe/form.php:
--------------------------------------------------------------------------------
1 | field($generator, 'loginModelClass');
7 | echo $form->field($generator, 'controllerClass');
8 | echo $form->field($generator, 'viewPath');
9 | echo $form->field($generator, 'baseControllerClass');
10 | echo $form->field($generator, 'enableI18N')->checkbox();
11 | echo $form->field($generator, 'messageCategory');
12 |
--------------------------------------------------------------------------------
/src/grid/ActionColumn.php:
--------------------------------------------------------------------------------
1 |
30 | * @since 1.0
31 | */
32 | class ActionColumn extends \yii\grid\ActionColumn
33 | {
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public $template = '{view} {update} {delete}{restore}';
38 |
39 |
40 | /**
41 | * Merges buttons with default configurations.
42 | */
43 | protected function initDefaultButtons()
44 | {
45 | $this->buttons = ArrayHelper::merge(
46 | [
47 | 'view' => [
48 | 'icon' => 'eye-open',
49 | 'options' => [
50 | 'title' => Yii::t('yii', 'View'),
51 | 'aria-label' => Yii::t('yii', 'View'),
52 | 'data-pjax' => '0',
53 | ],
54 | ],
55 | 'update' => [
56 | 'icon' => 'pencil',
57 | 'options' => [
58 | 'title' => Yii::t('yii', 'Update'),
59 | 'aria-label' => Yii::t('yii', 'Update'),
60 | 'data-pjax' => '0',
61 | ],
62 | ],
63 | 'delete' => [
64 | 'icon' => 'trash',
65 | 'visible' => function ($model) {
66 | /* @var $model \yii\db\BaseActiveRecord */
67 | if (is_object($model) && $model->canGetProperty('isDeleted')) {
68 | return !$model->isDeleted;
69 | }
70 | return true;
71 | },
72 | 'options' => [
73 | 'title' => Yii::t('yii', 'Delete'),
74 | 'aria-label' => Yii::t('yii', 'Delete'),
75 | 'data-confirm' => Yii::t('yii', 'Are you sure you want to delete this item?'),
76 | 'data-method' => 'post',
77 | 'data-pjax' => '0',
78 | ],
79 | ],
80 | 'restore' => [
81 | 'icon' => 'repeat',
82 | 'visible' => function ($model) {
83 | /* @var $model \yii\db\BaseActiveRecord */
84 | if (is_object($model) && $model->canGetProperty('isDeleted')) {
85 | return $model->isDeleted;
86 | }
87 | return false;
88 | },
89 | 'options' => [
90 | 'title' => Yii::t('yii2tech-admin', 'Restore'),
91 | 'aria-label' => Yii::t('yii2tech-admin', 'Restore'),
92 | 'data-confirm' => Yii::t('yii2tech-admin', 'Are you sure you want to restore this item?'),
93 | 'data-method' => 'post',
94 | 'data-pjax' => '0',
95 | ],
96 | ],
97 | ],
98 | $this->buttons
99 | );
100 | }
101 |
102 | /**
103 | * {@inheritdoc}
104 | */
105 | protected function renderDataCellContent($model, $key, $index)
106 | {
107 | return preg_replace_callback('/\\{([\w\-\/]+)\\}/', function ($matches) use ($model, $key, $index) {
108 | $name = $matches[1];
109 | return $this->renderButton($name, $model, $key, $index);
110 | }, $this->template);
111 | }
112 |
113 | /**
114 | * Renders button.
115 | * @param string $name button name.
116 | * @param $model
117 | * @param $key
118 | * @param $index
119 | * @return string rendered HTML
120 | * @throws InvalidConfigException on invalid button format.
121 | */
122 | protected function renderButton($name, $model, $key, $index)
123 | {
124 | if (!isset($this->buttons[$name])) {
125 | return '';
126 | }
127 | $button = $this->buttons[$name];
128 |
129 | if ($button instanceof \Closure) {
130 | $url = $this->createUrl($name, $model, $key, $index);
131 | return call_user_func($button, $url, $model, $key);
132 | }
133 | if (!is_array($button)) {
134 | throw new InvalidConfigException("Button should be either a Closure or array configuration.");
135 | }
136 |
137 | // Visibility :
138 | if (isset($button['visible'])) {
139 | if ($button['visible'] instanceof \Closure) {
140 | if (!call_user_func($button['visible'], $model, $key, $index)) {
141 | return '';
142 | }
143 | } elseif (!$button['visible']) {
144 | return '';
145 | }
146 | }
147 |
148 | // URL :
149 | if (isset($button['url'])) {
150 | $url = call_user_func($button['url'], $name, $model, $key, $index);
151 | } else {
152 | $url = $this->createUrl($name, $model, $key, $index);
153 | }
154 |
155 | // label :
156 | if (isset($button['label'])) {
157 | $label = $button['label'];
158 |
159 | if (isset($button['encode'])) {
160 | $encodeLabel = $button['encode'];
161 | unset($button['encode']);
162 | } else {
163 | $encodeLabel = true;
164 | }
165 | if ($encodeLabel) {
166 | $label = Html::encode($label);
167 | }
168 | } else {
169 | $label = '';
170 | }
171 |
172 | // icon :
173 | if (isset($button['icon'])) {
174 | $icon = $button['icon'];
175 | $label = Html::icon($icon) . (empty($label) ? '' : ' ' . $label);
176 | }
177 |
178 | $options = array_merge(ArrayHelper::getValue($button, 'options', []), $this->buttonOptions);
179 |
180 | return Html::a($label, $url, $options);
181 | }
182 |
183 | /**
184 | * {@inheritdoc}
185 | */
186 | public function createUrl($action, $model, $key, $index)
187 | {
188 | if (is_callable($this->urlCreator)) {
189 | return call_user_func($this->urlCreator, $action, $model, $key, $index);
190 | }
191 |
192 | $params = is_array($key) ? $key : ['id' => (string) $key];
193 | $params[0] = $this->controller ? $this->controller . '/' . $action : $action;
194 | $params = $params + Yii::$app->request->getQueryParams(); // preserve numeric keys
195 | return Url::toRoute($params);
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/grid/DeleteStatusColumn.php:
--------------------------------------------------------------------------------
1 | statusId)) {
35 | * // filter is not set - display only actual records :
36 | * $query->andWhere(['not', ['statusId' => Item::STATUS_DELETED]]);
37 | * } elseif($this->statusId > 0) {
38 | * // 'show all' is not selected - apply filter :
39 | * $query->andFilterWhere(['statusId' => $this->statusId]);
40 | * }
41 | *
42 | * // ...
43 | * }
44 | * }
45 | * ```
46 | *
47 | * @author Paul Klimov
48 | * @since 1.0
49 | */
50 | class DeleteStatusColumn extends DataColumn
51 | {
52 | /**
53 | * {@inheritdoc}
54 | */
55 | public $format = null;
56 | /**
57 | * @var mixed value, which indicates 'show all records' entry in the filter drop down.
58 | */
59 | public $filterAllValue = '-1';
60 |
61 |
62 | /**
63 | * {@inheritdoc}
64 | */
65 | public function init()
66 | {
67 | parent::init();
68 | if ($this->format === null) {
69 | if (stripos($this->attribute, 'deleted') !== false || stripos($this->attribute, 'active') !== false) {
70 | $this->format = 'boolean';
71 | } else {
72 | $this->format = 'text';
73 | }
74 | }
75 | }
76 |
77 | /**
78 | * {@inheritdoc}
79 | */
80 | protected function renderFilterCellContent()
81 | {
82 | if (is_string($this->filter)) {
83 | return $this->filter;
84 | }
85 |
86 | $model = $this->grid->filterModel;
87 |
88 | if ($this->filter !== false && $model instanceof Model && $this->attribute !== null && $model->isAttributeActive($this->attribute)) {
89 | if ($model->hasErrors($this->attribute)) {
90 | Html::addCssClass($this->filterOptions, 'has-error');
91 | $error = ' ' . Html::error($model, $this->attribute, $this->grid->filterErrorOptions);
92 | } else {
93 | $error = '';
94 | }
95 | if (is_array($this->filter)) {
96 | $filterItems = $this->filter;
97 | $filterItems[$this->filterAllValue] = Yii::t('yii2tech-admin', 'All records');
98 | } else {
99 | $filterItems = [
100 | '0' => Yii::t('yii2tech-admin', 'Deleted'),
101 | $this->filterAllValue => Yii::t('yii2tech-admin', 'All records')
102 | ];
103 | }
104 | $options = array_merge(['prompt' => Yii::t('yii2tech-admin', 'Actual only')], $this->filterInputOptions);
105 | return Html::activeDropDownList($model, $this->attribute, $filterItems, $options) . $error;
106 | }
107 |
108 | return parent::renderFilterCellContent();
109 | }
110 | }
--------------------------------------------------------------------------------
/src/grid/PositionColumn.php:
--------------------------------------------------------------------------------
1 |
23 | * @since 1.0
24 | */
25 | class PositionColumn extends DataColumn
26 | {
27 | /**
28 | * {@inheritdoc}
29 | */
30 | public $headerOptions = ['class' => 'position-column'];
31 | /**
32 | * @var string the template that is used to render the content in each cell.
33 | * These default tokens are recognized: {first}, {prev}, {next}, {last} and {value}.
34 | */
35 | public $template = '{first} {prev} {value} {next} {last}';
36 | /**
37 | * @var array configuration for the switch position buttons.
38 | */
39 | public $buttons = [];
40 | /**
41 | * @var array html options to be applied to the [[initDefaultButtons()|default buttons]].
42 | */
43 | public $buttonOptions = [];
44 | /**
45 | * @var string route to the action, which should process position switching, for example: 'item/position'.
46 | */
47 | public $route = 'position';
48 | /**
49 | * @var string name of the query param, which is used for new position specification.
50 | */
51 | public $positionParam = 'at';
52 | /**
53 | * @var callable a callback that creates a button URL using the specified model information.
54 | * The signature of the callback should be the same as that of [[createUrl()]].
55 | * If this property is not set, button URLs will be created using [[createUrl()]].
56 | */
57 | public $urlCreator;
58 |
59 |
60 | /**
61 | * {@inheritdoc}
62 | */
63 | public function init()
64 | {
65 | parent::init();
66 | $this->initDefaultButtons();
67 | }
68 |
69 | /**
70 | * Initializes the default buttons.
71 | */
72 | protected function initDefaultButtons()
73 | {
74 | $this->buttons = ArrayHelper::merge(
75 | [
76 | 'first' => [
77 | 'icon' => 'triangle-top',
78 | 'visible' => function ($model) {
79 | /* @var $model \yii\db\BaseActiveRecord */
80 | if ($this->attribute !== null && isset($model[$this->attribute])) {
81 | return $model[$this->attribute] > 1;
82 | }
83 | return true;
84 | },
85 | 'options' => [
86 | 'title' => Yii::t('yii2tech-admin', 'Move top'),
87 | 'aria-label' => Yii::t('yii2tech-admin', 'Move top'),
88 | ],
89 | ],
90 | 'last' => [
91 | 'icon' => 'triangle-bottom',
92 | 'visible' => function ($model) {
93 | /* @var $model \yii\db\BaseActiveRecord */
94 | if ($this->attribute !== null && isset($model[$this->attribute])) {
95 | return $model[$this->attribute] < $this->grid->dataProvider->getTotalCount();
96 | }
97 | return true;
98 | },
99 | 'options' => [
100 | 'title' => Yii::t('yii2tech-admin', 'Move bottom'),
101 | 'aria-label' => Yii::t('yii2tech-admin', 'Move bottom'),
102 | ],
103 | ],
104 | 'prev' => [
105 | 'icon' => 'arrow-up',
106 | 'visible' => function ($model) {
107 | /* @var $model \yii\db\BaseActiveRecord */
108 | if ($this->attribute !== null && isset($model[$this->attribute])) {
109 | return $model[$this->attribute] > 1;
110 | }
111 | return true;
112 | },
113 | 'options' => [
114 | 'title' => Yii::t('yii2tech-admin', 'Move up'),
115 | 'aria-label' => Yii::t('yii2tech-admin', 'Move up'),
116 | ],
117 | ],
118 | 'next' => [
119 | 'icon' => 'arrow-down',
120 | 'visible' => function ($model) {
121 | /* @var $model \yii\db\BaseActiveRecord */
122 | if ($this->attribute !== null && isset($model[$this->attribute])) {
123 | return $model[$this->attribute] < $this->grid->dataProvider->getTotalCount();
124 | }
125 | return true;
126 | },
127 | 'options' => [
128 | 'title' => Yii::t('yii2tech-admin', 'Move down'),
129 | 'aria-label' => Yii::t('yii2tech-admin', 'Move down'),
130 | ],
131 | ],
132 | ],
133 | $this->buttons
134 | );
135 | }
136 |
137 | /**
138 | * {@inheritdoc}
139 | */
140 | protected function renderDataCellContent($model, $key, $index)
141 | {
142 | if ($this->content === null) {
143 | return preg_replace_callback('/\\{([\w\-\/]+)\\}/', function ($matches) use ($model, $key, $index) {
144 | $name = $matches[1];
145 | if ($name === 'value') {
146 | return $this->grid->formatter->format($this->getDataCellValue($model, $key, $index), $this->format);
147 | }
148 | return $this->renderButton($name, $model, $key, $index);
149 | }, $this->template);
150 | }
151 |
152 | return parent::renderDataCellContent($model, $key, $index);
153 | }
154 |
155 | /**
156 | * Renders button.
157 | * @param string $name button name.
158 | * @param mixed $model
159 | * @param string $key
160 | * @param integer $index
161 | * @return string rendered HTML
162 | * @throws InvalidConfigException on invalid button format.
163 | */
164 | protected function renderButton($name, $model, $key, $index)
165 | {
166 | if (!isset($this->buttons[$name])) {
167 | return '';
168 | }
169 | $button = $this->buttons[$name];
170 |
171 | if ($button instanceof \Closure) {
172 | $url = $this->createUrl($name, $model, $key, $index);
173 | return call_user_func($button, $url, $model, $key);
174 | }
175 | if (!is_array($button)) {
176 | throw new InvalidConfigException("Button should be either a Closure or array configuration.");
177 | }
178 |
179 | // Visibility :
180 | if (isset($button['visible'])) {
181 | if ($button['visible'] instanceof \Closure) {
182 | if (!call_user_func($button['visible'], $model, $key, $index)) {
183 | return '';
184 | }
185 | } elseif (!$button['visible']) {
186 | return '';
187 | }
188 | }
189 |
190 | // URL :
191 | if (isset($button['url'])) {
192 | $url = call_user_func($button['url'], $name, $model, $key, $index);
193 | } else {
194 | $url = $this->createUrl($name, $model, $key, $index);
195 | }
196 |
197 | // label :
198 | if (isset($button['label'])) {
199 | $label = $button['label'];
200 |
201 | if (isset($button['encode'])) {
202 | $encodeLabel = $button['encode'];
203 | unset($button['encode']);
204 | } else {
205 | $encodeLabel = true;
206 | }
207 | if ($encodeLabel) {
208 | $label = Html::encode($label);
209 | }
210 | } else {
211 | $label = '';
212 | }
213 |
214 | // icon :
215 | if (isset($button['icon'])) {
216 | $icon = $button['icon'];
217 | $label = Html::icon($icon) . (empty($label) ? '' : ' ' . $label);
218 | }
219 |
220 | $options = array_merge(ArrayHelper::getValue($button, 'options', []), $this->buttonOptions);
221 |
222 | return Html::a($label, $url, $options);
223 | }
224 |
225 | /**
226 | * Creates a URL for the given position and model.
227 | * This method is called for each button and each row.
228 | * @param string $position the position name
229 | * @param \yii\db\BaseActiveRecord $model the data model
230 | * @param mixed $key the key associated with the data model
231 | * @param integer $index the current row index
232 | * @return string the created URL
233 | */
234 | public function createUrl($position, $model, $key, $index)
235 | {
236 | if (is_callable($this->urlCreator)) {
237 | return call_user_func($this->urlCreator, $position, $model, $key, $index);
238 | }
239 |
240 | $params = array_merge(
241 | Yii::$app->getRequest()->getQueryParams(),
242 | is_array($key) ? $key : ['id' => (string) $key]
243 | );
244 | $params[$this->positionParam] = $position;
245 | $params[0] = $this->route;
246 |
247 | return Url::toRoute($params);
248 | }
249 | }
--------------------------------------------------------------------------------
/src/grid/VariationColumn.php:
--------------------------------------------------------------------------------
1 |
20 | * @since 1.0
21 | */
22 | class VariationColumn extends DataColumn
23 | {
24 | /**
25 | * @var string model variation behavior name, which should be used by this column.
26 | * It should refer to [[\yii2tech\ar\variation\VariationBehavior]] instance.
27 | * If not set - model itself will be used for the method invocations.
28 | */
29 | public $variationName;
30 | /**
31 | * @var string name of the variation model attribute.
32 | * If not set [[attribute]] value will be used.
33 | */
34 | public $variationAttribute;
35 | /**
36 | * @var string|callable variation label source. This should be either a string - variation option
37 | * model attribute, which value should be used as variation label, or a callback of following signature:
38 | *
39 | * ```php
40 | * function ($mainModel, $variationModel) {
41 | * // return string label
42 | * }
43 | * ```
44 | */
45 | public $variationLabel;
46 | /**
47 | * @var array the HTML attributes for the variation table element.
48 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
49 | */
50 | public $tableOptions = ['class' => 'table table-bordered table-condensed', 'style' => 'margin-bottom:0px;'];
51 |
52 | /**
53 | * @var array internal cache for variation labels.
54 | */
55 | private $_variationLabels;
56 |
57 |
58 | /**
59 | * {@inheritdoc}
60 | */
61 | protected function renderDataCellContent($model, $key, $index)
62 | {
63 | if ($this->content === null) {
64 | $contentParts = [];
65 | $variationBehavior = $this->getVariationBehavior($model);
66 | foreach ($variationBehavior->getVariationModels() as $variationModel) {
67 | $contentParts[] = '' . $this->getVariationLabel($model, $variationModel) . ' | ' . $this->getVariationValue($variationModel) . ' | ';
68 | }
69 | return Html::tag('table', implode("\n", $contentParts), $this->tableOptions);
70 | }
71 |
72 | return parent::renderDataCellContent($model, $key, $index);
73 | }
74 |
75 | /**
76 | * Returns the variation value.
77 | * @param \yii\base\Model $variationModel variation model instance.
78 | * @return string value.
79 | */
80 | protected function getVariationValue($variationModel)
81 | {
82 | $attribute = $this->variationAttribute === null ? $this->attribute : $this->variationAttribute;
83 | return $this->grid->formatter->format($variationModel->{$attribute}, $this->format);
84 | }
85 |
86 | /**
87 | * Returns the variation label.
88 | * @param \yii\base\Model|\yii2tech\ar\variation\VariationBehavior $mainModel main model instance.
89 | * @param \yii\base\Model $variationModel variation model instance.
90 | * @return string label.
91 | * @throws InvalidConfigException on empty [[variationLabel]] value.
92 | */
93 | protected function getVariationLabel($mainModel, $variationModel)
94 | {
95 | if (empty($this->variationLabel)) {
96 | throw new InvalidConfigException('"' . get_class($this) . '::$variationLabel" must be specified');
97 | }
98 | if (!is_string($this->variationLabel)) {
99 | return call_user_func($this->variationLabel, $mainModel, $variationModel);
100 | }
101 |
102 | $variationLabels = $this->getVariationLabels($mainModel, $this->variationLabel);
103 |
104 | $variationBehavior = $this->getVariationBehavior($mainModel);
105 | $referenceAttribute = $variationBehavior->variationOptionReferenceAttribute;
106 | $variationPk = $variationModel->$referenceAttribute;
107 |
108 | if (isset($variationLabels[$variationPk])) {
109 | return $variationLabels[$variationPk];
110 | }
111 |
112 | return $variationModel->$referenceAttribute;
113 | }
114 |
115 | /**
116 | * Returns all available variation labels.
117 | * @param \yii\base\Model $mainModel main model instance.
118 | * @param string $labelAttribute name of the attribute, which is used as label source.
119 | * @return array list labels in format: optionPk => label
120 | */
121 | protected function getVariationLabels($mainModel, $labelAttribute)
122 | {
123 | if (!isset($this->_variationLabels[$labelAttribute])) {
124 | /* @var $optionClass \yii\db\ActiveRecordInterface */
125 | $variationBehavior = $this->getVariationBehavior($mainModel);
126 | $optionClass = $variationBehavior->optionModelClass;
127 | foreach ($optionClass::find()->all() as $optionModel) {
128 | /* @var $optionModel \yii\db\ActiveRecordInterface */
129 | $this->_variationLabels[$labelAttribute][$optionModel->getPrimaryKey()] = $optionModel->$labelAttribute;
130 | }
131 | }
132 | return $this->_variationLabels[$labelAttribute];
133 | }
134 |
135 | /**
136 | * Gets the variation behavior from model.
137 | * @param \yii\base\Model $model model instance.
138 | * @return \yii2tech\ar\variation\VariationBehavior variation behavior instance.
139 | */
140 | protected function getVariationBehavior($model)
141 | {
142 | return $this->variationName === null ? $model : $model->getBehavior($this->variationName);
143 | }
144 | }
--------------------------------------------------------------------------------
/src/messages/config.php:
--------------------------------------------------------------------------------
1 | __DIR__ . DIRECTORY_SEPARATOR . '..',
6 | // array, required, list of language codes that the extracted messages
7 | // should be translated to. For example, ['zh-CN', 'de'].
8 | 'languages' => ['en', 'es', 'it', 'pt-BR', 'ru', 'uk'],
9 | // string, the name of the function for translating messages.
10 | // Defaults to 'Yii::t'. This is used as a mark to find the messages to be
11 | // translated. You may use a string for single function name or an array for
12 | // multiple function names.
13 | 'translator' => 'Yii::t',
14 | // boolean, whether to sort messages by keys when merging new messages
15 | // with the existing ones. Defaults to false, which means the new (untranslated)
16 | // messages will be separated from the old (translated) ones.
17 | 'sort' => true,
18 | // boolean, whether to remove messages that no longer appear in the source code.
19 | // Defaults to false, which means each of these messages will be enclosed with a pair of '@@' marks.
20 | 'removeUnused' => false,
21 | // array, list of patterns that specify which files (not directories) should be processed.
22 | // If empty or not set, all files will be processed.
23 | // Please refer to "except" for details about the patterns.
24 | 'only' => ['*.php'],
25 | // array, list of patterns that specify which files/directories should NOT be processed.
26 | // If empty or not set, all files/directories will be processed.
27 | // A path matches a pattern if it contains the pattern string at its end. For example,
28 | // '/a/b' will match all files and directories ending with '/a/b';
29 | // the '*.svn' will match all files and directories whose name ends with '.svn'.
30 | // and the '.svn' will match all files and directories named exactly '.svn'.
31 | // Note, the '/' characters in a pattern matches both '/' and '\'.
32 | // See helpers/FileHelper::findFiles() description for more details on pattern matching rules.
33 | // If a file/directory matches both a pattern in "only" and "except", it will NOT be processed.
34 | 'except' => [
35 | '.svn',
36 | '.git',
37 | '.gitignore',
38 | '.gitkeep',
39 | '.hgignore',
40 | '.hgkeep',
41 | '/messages',
42 | '/tests',
43 | '/runtime',
44 | '/vendor',
45 | ],
46 |
47 | // 'php' output format is for saving messages to php files.
48 | 'format' => 'php',
49 | // Root directory containing message translations.
50 | 'messagePath' => __DIR__,
51 | // boolean, whether the message file should be overwritten with the merged messages
52 | 'overwrite' => true,
53 |
54 | // Message categories to ignore
55 | 'ignoreCategories' => [
56 | 'yii',
57 | ],
58 | ];
59 |
--------------------------------------------------------------------------------
/src/messages/en/yii2tech-admin.php:
--------------------------------------------------------------------------------
1 | 'Actual only',
21 | 'All records' => 'All records',
22 | 'Are you sure you want to restore defaults?' => 'Are you sure you want to restore defaults?',
23 | 'Are you sure you want to restore this item?' => 'Are you sure you want to restore this item?',
24 | 'Back' => 'Back',
25 | 'Context \'{name}\' required.' => 'Context \'{name}\' required.',
26 | 'Context object not found: {id}' => 'Context object not found: {id}',
27 | 'Create' => 'Create',
28 | 'Delete' => 'Delete',
29 | 'Deleted' => 'Deleted',
30 | 'Do it now' => 'Do it now',
31 | 'Import' => 'Import',
32 | 'Move bottom' => 'Move bottom',
33 | 'Move down' => 'Move down',
34 | 'Move top' => 'Move top',
35 | 'Move up' => 'Move up',
36 | 'Object not found: {id}' => 'Object not found: {id}',
37 | 'Restore' => 'Restore',
38 | 'Restore Defaults' => 'Restore Defaults',
39 | 'Update' => 'Update',
40 | 'View' => 'View',
41 | ];
42 |
--------------------------------------------------------------------------------
/src/messages/es/yii2tech-admin.php:
--------------------------------------------------------------------------------
1 | 'Actual unicamente',
21 | 'All records' => 'Todos los Registro',
22 | 'Are you sure you want to restore defaults?' => '¿Esta seguro que quiere restaurar por defecto?',
23 | 'Are you sure you want to restore this item?' => '¿Esta seguro que quiere restaurar este artículo',
24 | 'Back' => 'Volver',
25 | 'Context \'{name}\' required.' => 'Contexto \'{name}\' requerido.',
26 | 'Context object not found: {id}' => 'Objeto de contexto no encontrado: {id}',
27 | 'Create' => 'Сrear',
28 | 'Delete' => 'Borrar',
29 | 'Deleted' => 'Borrado',
30 | 'Do it now' => 'Hacerlo ahora',
31 | 'Import' => 'Importar',
32 | 'Move bottom' => 'Mover al fondo',
33 | 'Move down' => 'Mover abajo',
34 | 'Move top' => 'Mover al tope',
35 | 'Move up' => 'Mover arriva',
36 | 'Object not found: {id}' => 'Objeto no encontrado: {id}',
37 | 'Restore' => 'Restaurar',
38 | 'Restore Defaults' => 'Restaurar valores por defecto',
39 | 'Update' => 'Actualizar',
40 | 'View' => 'Ver',
41 | ];
42 |
--------------------------------------------------------------------------------
/src/messages/it/yii2tech-admin.php:
--------------------------------------------------------------------------------
1 | 'Actual only',
21 | 'All records' => 'Tutti i record',
22 | 'Are you sure you want to restore defaults?' => 'Sei sicuro di voler ripristinare i predefiniti?',
23 | 'Are you sure you want to restore this item?' => 'Sei sicuro di voler ripristinare questo elemento?',
24 | 'Back' => 'Indietro',
25 | 'Context \'{name}\' required.' => 'Contesto \'{name}\' richiesto.',
26 | 'Context object not found: {id}' => 'Oggetto del contesto {id} non trovato',
27 | 'Create' => 'Nuovo',
28 | 'Delete' => 'Cancella',
29 | 'Deleted' => 'Cancellato',
30 | 'Do it now' => 'Farlo ora',
31 | 'Import' => 'Importa',
32 | 'Move bottom' => 'Sposta in fondo',
33 | 'Move down' => 'Sposta in giù',
34 | 'Move top' => 'Sposta in cima',
35 | 'Move up' => 'Sposta in su',
36 | 'Object not found: {id}' => 'Oggetto non trovato: {id}',
37 | 'Restore' => 'Ripristina',
38 | 'Restore Defaults' => 'Ripristina predefiniti',
39 | 'Update' => 'Modifica',
40 | 'View' => 'Visualizza',
41 | ];
42 |
--------------------------------------------------------------------------------
/src/messages/pt-BR/yii2tech-admin.php:
--------------------------------------------------------------------------------
1 | 'Apenas atual',
21 | 'All records' => 'Todos registros',
22 | 'Are you sure you want to restore defaults?' => 'Tem certeza de que deseja restaurar os padrões?',
23 | 'Are you sure you want to restore this item?' => 'Tem certeza de que deseja restaurar este item?',
24 | 'Back' => 'Voltar',
25 | 'Context \'{name}\' required.' => 'Contexto \'{name}\' necessário.',
26 | 'Context object not found: {id}' => 'Contexto objeto não encontrado: {id}',
27 | 'Create' => 'Criar',
28 | 'Delete' => 'Excluir',
29 | 'Deleted' => 'Excluído',
30 | 'Do it now' => 'Fazê-lo agora',
31 | 'Import' => 'Importar',
32 | 'Move bottom' => 'Mover inferior',
33 | 'Move down' => 'Mover para baixo',
34 | 'Move top' => 'Mover topo',
35 | 'Move up' => 'Mover para cima',
36 | 'Object not found: {id}' => 'Objeto não encontrado: {id}',
37 | 'Restore' => 'Restaurar',
38 | 'Restore Defaults' => 'Restaurar padrões',
39 | 'Update' => 'Atualizar',
40 | 'View' => 'Visualizar',
41 | ];
42 |
--------------------------------------------------------------------------------
/src/messages/ru/yii2tech-admin.php:
--------------------------------------------------------------------------------
1 | 'Только актуальные',
21 | 'All records' => 'Все записи',
22 | 'Are you sure you want to restore defaults?' => 'Вы уверены, что хотите восстановить значения по умолчанию?',
23 | 'Are you sure you want to restore this item?' => 'Вы уверены, что хотите восстановить этот элемент?',
24 | 'Back' => 'Назад',
25 | 'Context \'{name}\' required.' => 'Контекст \'{name}\' должен быть задан.',
26 | 'Context object not found: {id}' => 'Контекстный объект не найден: {id}',
27 | 'Create' => 'Создать',
28 | 'Delete' => 'Удалить',
29 | 'Deleted' => 'Удалено',
30 | 'Do it now' => 'Выполнить сейчас',
31 | 'Import' => 'Импорт',
32 | 'Move bottom' => 'Переместить в конец',
33 | 'Move down' => 'Переместить вниз',
34 | 'Move top' => 'Переместить в начало',
35 | 'Move up' => 'Переместить вверх',
36 | 'Object not found: {id}' => 'Объект не найден: {id}',
37 | 'Restore' => 'Восстановить',
38 | 'Restore Defaults' => 'По умолчанию',
39 | 'Update' => 'Редактировать',
40 | 'View' => 'Просмотр',
41 | ];
42 |
--------------------------------------------------------------------------------
/src/messages/uk/yii2tech-admin.php:
--------------------------------------------------------------------------------
1 | 'Тільки актуальні',
21 | 'All records' => 'Усі записи',
22 | 'Are you sure you want to restore defaults?' => 'Ви впевнені, що хочете відновити стандартні значення?',
23 | 'Are you sure you want to restore this item?' => 'Ви впевнені, що хочете відновити цей елемент?',
24 | 'Back' => 'Назад',
25 | 'Context \'{name}\' required.' => 'Контекст \'{name}\' має бути заданий.',
26 | 'Context object not found: {id}' => 'Котекстний об\'єкт не знайдено: {id}',
27 | 'Create' => 'Створити',
28 | 'Delete' => 'Видалити',
29 | 'Deleted' => 'Видалено',
30 | 'Do it now' => 'Виконати зараз',
31 | 'Import' => 'Імпорт',
32 | 'Move bottom' => 'Перемістити в кінець',
33 | 'Move down' => 'Перемістити вниз',
34 | 'Move top' => 'Перемістити на початок',
35 | 'Move up' => 'Перемістити вгору',
36 | 'Object not found: {id}' => 'Об\'єкт не знайдено: {id}',
37 | 'Restore' => 'Відновити',
38 | 'Restore Defaults' => 'Відновити стандарт',
39 | 'Update' => 'Оновити',
40 | 'View' => 'Переглянути',
41 | ];
42 |
--------------------------------------------------------------------------------
/src/widgets/ActionAlert.php:
--------------------------------------------------------------------------------
1 |
33 | * @since 1.0.1
34 | */
35 | class ActionAlert extends Widget
36 | {
37 | /**
38 | * @var array[] list of actions to be displayed. Each item should be an array of following structure:
39 | *
40 | * - title: string, optional, alert title as HTML (it will not be html-encoded). If not set - it will be composed from
41 | * action key in array using [[Inflector]].
42 | * - url: array|string, action URL.
43 | * - visible: bool|callable, optional, condition, which check should be successful in order to make alert visible.
44 | * If not set - visibility is determined by value of the session variable, which names is equal to the action key in array.
45 | * - linkText: string, optional, action link text.
46 | * - linkOptions: array, optional, action link HTML options.
47 | *
48 | * For example:
49 | *
50 | * ```php
51 | * [
52 | * 'cacheFlushRequired' => [
53 | * 'title' => 'Cache Flush Required',
54 | * 'url' => ['/maintenance/flush-cache'],
55 | * ],
56 | * 'siteMapRegenerationRequired' => [
57 | * 'title' => 'Sitemap regeneration Required',
58 | * 'linkText' => 'Regenerate Sitemap',
59 | * 'url' => ['/sitemap/generate'],
60 | * 'visible' => function () {
61 | * return SiteMapActiveRecord::find()->max('createdAt') < PageActiveRecord::find->max('createdAt');
62 | * },
63 | * ],
64 | * ]
65 | * ```
66 | */
67 | public $actions = [];
68 | /**
69 | * @var string alert body layout. Following placeholders are available:
70 | *
71 | * - {title} - Alert title text.
72 | * - {link} - link button HTML.
73 | */
74 | public $layout = '{title} {link}';
75 | /**
76 | * @var array the HTML attributes for the alert widget container tag.
77 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
78 | */
79 | public $options = [
80 | 'class' => 'alert-warning'
81 | ];
82 | /**
83 | * @var array|false the options for rendering the alert close button tag.
84 | */
85 | public $closeButton = false;
86 |
87 |
88 | /**
89 | * {@inheritdoc}
90 | */
91 | public function run()
92 | {
93 | $alerts = [];
94 |
95 | foreach ($this->actions as $key => $action) {
96 | $action = array_merge(
97 | [
98 | 'title' => '',
99 | 'url' => '',
100 | 'linkText' => '',
101 | 'linkOptions' => [
102 | 'class' => 'btn btn-warning',
103 | ],
104 | ],
105 | $action
106 | );
107 |
108 | if (!isset($action['visible'])) {
109 | $action['visible'] = function () use ($key) {
110 | return (bool)Yii::$app->session->get($key, false);
111 | };
112 | }
113 |
114 | if (is_bool($action['visible'])) {
115 | if ($action['visible']) {
116 | continue;
117 | }
118 | } else {
119 | if (!call_user_func($action['visible'])) {
120 | continue;
121 | }
122 | }
123 |
124 | Html::addCssClass($action['linkOptions'], ['widget' => 'btn-action-alert']);
125 |
126 | if (empty($action['title'])) {
127 | $action['title'] = Inflector::camel2words(Inflector::humanize($key));
128 | }
129 | if (empty($action['linkText'])) {
130 | $action['linkText'] = Yii::t('yii2tech-admin', 'Do it now');
131 | }
132 |
133 | $body = strtr($this->layout, [
134 | '{title}' => $action['title'],
135 | '{link}' => Html::a($action['linkText'], $action['url'], $action['linkOptions']),
136 | ]);
137 |
138 | $alerts[] = Alert::widget([
139 | 'body' => $body,
140 | 'closeButton' => $this->closeButton,
141 | 'options' => $this->options,
142 | ]);
143 | }
144 |
145 | return implode("\n", $alerts);
146 | }
147 | }
--------------------------------------------------------------------------------
/src/widgets/Alert.php:
--------------------------------------------------------------------------------
1 | session->setFlash('error', 'This is the message');
20 | * Yii::$app->session->setFlash('success', 'This is the message');
21 | * Yii::$app->session->setFlash('info', 'This is the message');
22 | * ```
23 | *
24 | * Multiple messages could be set as following:
25 | *
26 | * ```php
27 | * Yii::$app->session->setFlash('error', ['Error 1', 'Error 2']);
28 | * ```
29 | *
30 | * Since 1.0.3 alert type is determined via wildcard match, so messages could be set as following:
31 | *
32 | * ```php
33 | * Yii::$app->session->setFlash('saveSuccess', 'This is the success message');
34 | * Yii::$app->session->setFlash('errorSave', 'This is the error message');
35 | * ```
36 | *
37 | * @see \yii\bootstrap\Alert
38 | *
39 | * @author Kartik Visweswaran
40 | * @author Alexander Makarov
41 | * @author Paul Klimov
42 | * @since 1.0
43 | */
44 | class Alert extends Widget
45 | {
46 | /**
47 | * @var array the alert types configuration for the flash messages.
48 | * This array is setup as $key => $value, where:
49 | *
50 | * - $key is the case-insensitive wildcard pattern for the name of the session flash variable.
51 | * - $value is the bootstrap alert type (i.e. danger, success, info, warning).
52 | */
53 | public $alertTypes = [
54 | '*error*' => 'alert-danger',
55 | '*danger*' => 'alert-danger',
56 | '*success*' => 'alert-success',
57 | '*warning*' => 'alert-warning',
58 | '*' => 'alert-info',
59 | ];
60 | /**
61 | * @var array the options for rendering the close button tag.
62 | */
63 | public $closeButton = [];
64 |
65 |
66 | /**
67 | * {@inheritdoc}
68 | */
69 | public function run()
70 | {
71 | $session = Yii::$app->session;
72 | $flashes = $session->getAllFlashes();
73 | $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : '';
74 |
75 | $alerts = [];
76 | foreach ($flashes as $type => $data) {
77 | foreach ($this->alertTypes as $pattern => $css) {
78 | if (StringHelper::matchWildcard($pattern, $type, ['caseSensitive' => false])) {
79 | $data = (array) $data;
80 | foreach ($data as $i => $message) {
81 | /* initialize css class for each alert box */
82 | $this->options['class'] = $css . $appendCss;
83 |
84 | /* assign unique id to each alert box */
85 | $this->options['id'] = $this->getId() . '-' . $type . '-' . $i;
86 |
87 | $alerts[] = \yii\bootstrap\Alert::widget([
88 | 'body' => $message,
89 | 'closeButton' => $this->closeButton,
90 | 'options' => $this->options,
91 | ]);
92 | }
93 |
94 | $session->removeFlash($type);
95 | break;
96 | }
97 | }
98 | }
99 |
100 | return implode("\n", $alerts);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/widgets/ButtonContextMenu.php:
--------------------------------------------------------------------------------
1 |
19 | * @package yii2tech\admin\widgets
20 | */
21 | class ButtonContextMenu extends Widget
22 | {
23 | /**
24 | * @var array[] list of items. Each array element represents a single menu item, which should be an array.
25 | * Item array should have the following structure:
26 | *
27 | * - url: array, required, the item's URL.
28 | * - label: string, optional, the item label.
29 | * - encode: boolean, optional, whether to encode item label.
30 | * - icon: string, optional, item label icon short name.
31 | *
32 | * Any additional keys will be used as link tag options.
33 | *
34 | * If item array contains zero key, it will be taken as 'url' key.
35 | */
36 | public $items = [];
37 | /**
38 | * @var boolean whether the nav items labels should be HTML-encoded.
39 | */
40 | public $encodeLabels = true;
41 |
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function run()
47 | {
48 | $contentParts = [];
49 | foreach ($this->items as $item) {
50 | $contentParts[] = $this->renderItem($item);
51 | }
52 | return implode("\n", $contentParts);
53 | }
54 |
55 | /**
56 | * Renders single item.
57 | * @param array $item item configuration.
58 | * @return string rendered HTML
59 | */
60 | protected function renderItem($item)
61 | {
62 | if (isset($item[0])) {
63 | $url = $item;
64 | $options = [];
65 | } else {
66 | $url = $item['url'];
67 | $options = $item;
68 | unset($options['url']);
69 | }
70 |
71 | // label :
72 | if (isset($options['label'])) {
73 | $label = $options['label'];
74 | unset($options['label']);
75 | } else {
76 | $label = $this->detectLabel($url);
77 | }
78 | if (isset($options['encode'])) {
79 | $encodeLabel = $options['encode'];
80 | unset($options['encode']);
81 | } else {
82 | $encodeLabel = $this->encodeLabels;
83 | }
84 | if ($encodeLabel) {
85 | $label = Html::encode($label);
86 | }
87 |
88 | // icon :
89 | if (isset($options['icon'])) {
90 | $icon = $options['icon'];
91 | unset($options['icon']);
92 | } else {
93 | $icon = $this->detectIcon($url);
94 | }
95 | if ($icon) {
96 | $label = Html::icon($icon) . ' ' . $label;
97 | }
98 |
99 | // CSS class :
100 | if (isset($options['class'])) {
101 | Html::addCssClass($options, ['widget' => 'btn']);
102 | } else {
103 | $options['class'] = [
104 | 'btn',
105 | $this->detectClass($url)
106 | ];
107 | }
108 |
109 | if (!isset($options['data'])) {
110 | $options['data'] = $this->detectData($url);
111 | }
112 |
113 | return Html::a($label, $url, $options);
114 | }
115 |
116 | /**
117 | * @param array $url URL config.
118 | * @return string label
119 | */
120 | protected function detectLabel($url)
121 | {
122 | switch ($url[0]) {
123 | case 'index':
124 | return Yii::t('yii2tech-admin', 'Back');
125 | case 'create':
126 | return Yii::t('yii2tech-admin', 'Create');
127 | case 'update':
128 | return Yii::t('yii2tech-admin', 'Update');
129 | case 'delete':
130 | return Yii::t('yii2tech-admin', 'Delete');
131 | case 'view':
132 | return Yii::t('yii2tech-admin', 'View');
133 | case 'default':
134 | return Yii::t('yii2tech-admin', 'Restore Defaults');
135 | case 'import':
136 | return Yii::t('yii2tech-admin', 'Import');
137 | default:
138 | return ucfirst($url[0]);
139 | }
140 | }
141 |
142 | /**
143 | * @param array $url URL config
144 | * @return boolean|string icon short name, 'false' on failure
145 | */
146 | protected function detectIcon($url)
147 | {
148 | switch ($url[0]) {
149 | case 'index':
150 | return 'arrow-left';
151 | case 'create':
152 | return 'plus';
153 | case 'update':
154 | return 'pencil';
155 | case 'delete':
156 | return 'trash';
157 | case 'view':
158 | return 'eye-open';
159 | case 'default':
160 | return 'btn-repeat';
161 | case 'import':
162 | return 'import';
163 | default:
164 | return false;
165 | }
166 | }
167 |
168 | /**
169 | * @param array $url URL config
170 | * @return string CSS class.
171 | */
172 | protected function detectClass($url)
173 | {
174 | switch ($url[0]) {
175 | case 'index':
176 | return 'btn-default';
177 | case 'create':
178 | return 'btn-success';
179 | case 'update':
180 | return 'btn-primary';
181 | case 'delete':
182 | return 'btn-danger';
183 | case 'view':
184 | return 'btn-info';
185 | case 'default':
186 | return 'btn-danger';
187 | case 'import':
188 | return 'btn-success';
189 | default:
190 | return 'btn-default';
191 | }
192 | }
193 |
194 | /**
195 | * @param array $url URL config
196 | * @return array|null link data
197 | */
198 | protected function detectData($url)
199 | {
200 | switch ($url[0]) {
201 | case 'delete':
202 | return [
203 | 'confirm' => Yii::t('yii', 'Are you sure you want to delete this item?'),
204 | 'method' => 'post',
205 | ];
206 | case 'restore':
207 | return [
208 | 'confirm' => Yii::t('yii2tech-admin', 'Are you sure you want to restore this item?'),
209 | 'method' => 'post',
210 | ];
211 | case 'default':
212 | return [
213 | 'confirm' => Yii::t('yii2tech-admin', 'Are you sure you want to restore defaults?'),
214 | ];
215 | default:
216 | return null;
217 | }
218 | }
219 | }
--------------------------------------------------------------------------------
/src/widgets/Nav.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 1.0
20 | */
21 | class Nav extends \yii\bootstrap\Nav
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function renderItem($item)
27 | {
28 | return parent::renderItem($this->normalizeItem($item));
29 | }
30 |
31 | /**
32 | * @param string|array $item the item to be normalized.
33 | * @return string|array normalized item.
34 | */
35 | protected function normalizeItem($item)
36 | {
37 | if (is_array($item)) {
38 | if (isset($item['icon'])) {
39 | if (isset($item['label'])) {
40 | $label = $item['label'];
41 | $encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
42 | if ($encodeLabel) {
43 | $label = Html::encode($label);
44 | }
45 | } else {
46 | $label = '';
47 | }
48 | $item['encode'] = false;
49 | $label = Html::icon($item['icon']) . ' ' . $label;
50 | $item['label'] = $label;
51 | }
52 | if (isset($item['items'])) {
53 | foreach ($item['items'] as $key => $value) {
54 | $item['items'][$key] = $this->normalizeItem($value);
55 | }
56 | }
57 | }
58 | return $item;
59 | }
60 | }
--------------------------------------------------------------------------------