diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 15add402..e6680db0 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -19,3 +19,9 @@ jobs: cd tests make all make test + + - name: 'Upload Test Report' + uses: actions/upload-artifact@v4 + with: + path: tests/_output + retention-days: 7 diff --git a/src/commands/BatchController.php b/src/commands/BatchController.php index b72377ec..cfc4d89e 100644 --- a/src/commands/BatchController.php +++ b/src/commands/BatchController.php @@ -161,6 +161,16 @@ class BatchController extends Controller */ public $enableI18N = true; + /** + * @var bool whether to enable or disable the pluralization of the models name + */ + public $disablePluralization = false; + + /** + * @var string prefix to prepend to the many many relation methods + */ + public $modelManyManyRelationSuffix = ''; + /** * @var bool whether the entity names will be singular or the same as the table name */ @@ -299,13 +309,26 @@ class BatchController extends Controller * @var bool This indicates whether the generator should generate attribute hints by using the comments of the corresponding DB columns */ public $modelGenerateHintsFromComments = true; + + /** + * @var bool Generate Relations from Current Schema + */ + public $modelGenerateRelationsFromCurrentSchema = true; + + public $modelTranslationTableAdditions = ['name' => 'meta', 'fallbackLanguage' => false]; + + /** + * Whether the copy functionality for a crud should be created or not + */ + public $crudEnableCopy = true; + /** * @var array application configuration for creating temporary applications */ protected $appConfig; /** - * @var instance of class schmunk42\giiant\generators\model\Generator + * @var \schmunk42\giiant\generators\model\Generator instance of class schmunk42\giiant\generators\model\Generator */ protected $modelGenerator; @@ -345,6 +368,8 @@ public function options($id) 'modelRemoveDuplicateRelations', 'modelCacheRelationsData', 'modelGenerateRelations', + 'modelGenerateRelationsFromCurrentSchema', + 'modelTranslationTableAdditions', 'modelGenerateJunctionRelationMode', 'modelGenerateQuery', 'modelQueryNamespace', @@ -367,7 +392,9 @@ public function options($id) 'crudOverwriteSearchModelClass', 'crudOverwriteRestControllerClass', 'crudOverwriteControllerClass', - 'generateAccessFilterMigrations' + 'generateAccessFilterMigrations', + 'disablePluralization', + 'crudEnableCopy' ] ); } @@ -463,6 +490,8 @@ public function actionModels() 'removeDuplicateRelations' => $this->modelRemoveDuplicateRelations, 'cacheRelationsData' => $this->modelCacheRelationsData, 'generateRelations' => $this->modelGenerateRelations, + 'generateRelationsFromCurrentSchema' => $this->modelGenerateRelationsFromCurrentSchema, + 'translationTableAdditions' => $this->modelTranslationTableAdditions, 'generateJunctionRelationMode' => $this->modelGenerateJunctionRelationMode, 'tableNameMap' => $this->tableNameMap, 'generateQuery' => $this->modelGenerateQuery, @@ -470,6 +499,8 @@ public function actionModels() 'queryBaseClass' => $this->modelQueryBaseClass, 'generateLabelsFromComments' => $this->modelGenerateLabelsFromComments, 'generateHintsFromComments' => $this->modelGenerateHintsFromComments, + 'disablePluralization' => $this->disablePluralization, + 'manyManyRelationSuffix' => $this->modelManyManyRelationSuffix ]; $route = 'gii/giiant-model'; @@ -540,6 +571,9 @@ public function actionCruds() 'gridMaxColumns' => $this->crudGridMaxColumns, 'generateAccessFilterMigrations' => $this->generateAccessFilterMigrations, 'actionButtonColumnPosition' => $this->crudActionButtonColumnPosition, + 'disablePluralization' => $this->disablePluralization, + 'gridMaxColumns' => $this->crudGridMaxColumns, + 'enableCopy' => $this->crudEnableCopy ]; $route = 'gii/giiant-crud'; $app = \Yii::$app; @@ -612,9 +646,14 @@ private function closeTempAppConnections(Application $app) // since we don't know if there are any other than the "known" modelDb if (isset($app->components)) { foreach ($app->components as $cid => $component) { - $cObj = $app->get($cid); - if ($cObj instanceof \yii\db\Connection) { - $cObj->close(); + try { + $cObj = $app->get($cid); + if ($cObj instanceof \yii\db\Connection) { + $cObj->close(); + } + } catch (\Throwable $e) { + // ignore because we don't know if the component is a db connection + Yii::warning($e->getMessage()); } } } diff --git a/src/generators/crud/Generator.php b/src/generators/crud/Generator.php index c7bdcaa1..d11e22e4 100644 --- a/src/generators/crud/Generator.php +++ b/src/generators/crud/Generator.php @@ -138,6 +138,11 @@ class Generator extends \yii\gii\generators\crud\Generator */ public $fixOptions = ''; + /** + * @var bool whether to enable or disable the pluralization of the models name + */ + public $disablePluralization = false; + /** * @var string form field for selecting and loading saved gii forms */ @@ -158,6 +163,10 @@ class Generator extends \yii\gii\generators\crud\Generator private $_p = []; + public $translateRelations = ['translation', 'translation_meta']; + + public $enableCopy = true; + /** * {@inheritdoc} */ @@ -230,6 +239,7 @@ public function rules() 'generateAccessFilterMigrations', 'singularEntities', 'modelMessageCategory', + 'enableCopy' ], 'safe', ], @@ -270,6 +280,7 @@ public function formAttributes() 'accessFilter', 'singularEntities', 'modelMessageCategory', + 'enableCopy' ]; } @@ -305,20 +316,20 @@ public function getControllerID() public function getModuleId() { if (!$this->moduleNs) { - $controllerNs = \yii\helpers\StringHelper::dirname(ltrim($this->controllerClass, '\\')); - $this->moduleNs = \yii\helpers\StringHelper::dirname(ltrim($controllerNs, '\\')); + $controllerNs = StringHelper::dirname(ltrim($this->controllerClass, '\\')); + $this->moduleNs = StringHelper::dirname(ltrim($controllerNs, '\\')); } - return \yii\helpers\StringHelper::basename($this->moduleNs); + return StringHelper::basename($this->moduleNs); } public function generate() { $accessDefinitions = require $this->getTemplatePath().'/access_definition.php'; - $this->controllerNs = \yii\helpers\StringHelper::dirname(ltrim($this->controllerClass, '\\')); - $this->moduleNs = \yii\helpers\StringHelper::dirname(ltrim($this->controllerNs, '\\')); - $controllerName = substr(\yii\helpers\StringHelper::basename($this->controllerClass), 0, -10); + $this->controllerNs = StringHelper::dirname(ltrim($this->controllerClass, '\\')); + $this->moduleNs = StringHelper::dirname(ltrim($this->controllerNs, '\\')); + $controllerName = substr(StringHelper::basename($this->controllerClass), 0, -10); if ($this->singularEntities) { $this->modelClass = Inflector::singularize($this->modelClass); @@ -345,7 +356,7 @@ public function generate() } $files[] = new CodeFile($baseControllerFile, $this->render('controller.php', ['accessDefinitions' => $accessDefinitions])); - $params['controllerClassName'] = \yii\helpers\StringHelper::basename($this->controllerClass); + $params['controllerClassName'] = StringHelper::basename($this->controllerClass); if ($this->overwriteControllerClass || !is_file($controllerFile)) { $files[] = new CodeFile($controllerFile, $this->render('controller-extended.php', $params)); @@ -365,12 +376,32 @@ public function generate() $viewPath = $this->getViewPath(); $templatePath = $this->getTemplatePath().'/views'; + $model = Yii::createObject($this->modelClass); + if (array_key_exists('crud-form', $model->scenarios())) { + $model->setScenario('crud-form'); + } else { + $model->setScenario('crud'); + } + + $safeAttributes = $model->safeAttributes(); + if (empty($safeAttributes)) { + $model->setScenario('default'); + $safeAttributes = $model->safeAttributes(); + } + if (empty($safeAttributes)) { + $safeAttributes = $model::getTableSchema()->columnNames; + } + foreach (scandir($templatePath) as $file) { - if (empty($this->searchModelClass) && $file === '_search.php') { + if ($file === '_search.php' && !$this->getRenderWithSearch()) { continue; } if (is_file($templatePath.'/'.$file) && pathinfo($file, PATHINFO_EXTENSION) === 'php') { - $files[] = new CodeFile("$viewPath/$file", $this->render("views/$file", ['permisions' => $permisions])); + $files[] = new CodeFile("$viewPath/$file", $this->render("views/$file", [ + 'model' => $model, + 'safeAttributes' => $safeAttributes, + 'accessDefinitions' => $accessDefinitions + ])); } } @@ -462,4 +493,73 @@ public function var_export54($var, $indent = '') return var_export($var, true); } } + + /** + * @return array + * @throws \yii\base\InvalidConfigException + */ + public function generateSearchRules() + { + + $rules = parent::generateSearchRules(); + $model = \Yii::createObject($this->modelClass); + foreach ($model->behaviors() as $key => $behavior) { + if (!empty($behavior['translationAttributes'])) { + $rules[] = "[['" . implode("', '", $behavior['translationAttributes']) . "'], 'safe']"; + } + } + return $rules; + } + + /** + * @return array + * @throws \yii\base\InvalidConfigException + */ + public function generateSearchConditions() + { + + $searchConditions = parent::generateSearchConditions(); + $model = \Yii::createObject($this->modelClass); + foreach ($model->behaviors() as $key => $behavior) { + if (!empty($behavior['translationAttributes'])) { + foreach ($behavior['translationAttributes'] as $translationAttribute) { + $searchConditions[] = "\$query->andFilterWhere(['like','{$translationAttribute}', \$this->$translationAttribute]);"; + } + } + } + return $searchConditions; + } + + + /** + * @return array + */ + public function getTranslationRelationModels() + { + $translationRelationModels = []; + foreach ($this->translateRelations as $translateRelation) { + $translationRelationModels[] = $this->modelClass . Inflector::camelize($translateRelation); + } + return $translationRelationModels; + } + + /** + * @return string + */ + public function getTranslationModelClass() { + return '\\' . $this->modelClass . Inflector::camelize('translation'); + } + + /** + * @return bool + * @throws \yii\base\InvalidConfigException + */ + public function getHasTranslationRelation() { + return isset(\Yii::createObject($this->modelClass)->behaviors()['translation']); + } + + public function getRenderWithSearch() + { + return $this->indexWidgetType !== 'grid' && $this->searchModelClass !== ''; + } } diff --git a/src/generators/crud/ModelTrait.php b/src/generators/crud/ModelTrait.php index 037879d0..b265e280 100644 --- a/src/generators/crud/ModelTrait.php +++ b/src/generators/crud/ModelTrait.php @@ -63,7 +63,7 @@ public function getModelByTableName($name) * * return values can be filtered by types 'belongs_to', 'many_many', 'has_many', 'has_one', 'pivot' * - * @param ActiveRecord $modelClass + * @param \yii\db\ActiveRecord $modelClass * @param array $types * * @return array @@ -73,13 +73,15 @@ public function getModelRelations($modelClass, $types = []) $reflector = new \ReflectionClass($modelClass); $model = new $modelClass(); $stack = []; - $modelGenerator = new ModelGenerator(); + $modelGenerator = new ModelGenerator([ + 'disablePluralization' => $this->disablePluralization + ]); foreach ($reflector->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { - if (in_array(substr($method->name, 3), $this->skipRelations)) { + if (in_array(substr($method->name, 3), $this->skipRelations, true)) { continue; } // look for getters - if (substr($method->name, 0, 3) !== 'get') { + if (strpos($method->name, 'get') !== 0) { continue; } // skip class specific getters @@ -90,7 +92,7 @@ public function getModelRelations($modelClass, $types = []) 'getAttribute', 'getAttributeLabel', 'getAttributeHint', - 'getOldAttribute', + 'getOldAttribute', 'getErrorSummary', ]; if (in_array($method->name, $skipMethods)) { @@ -117,13 +119,17 @@ public function getModelRelations($modelClass, $types = []) $relationType = 'has_many'; } // if types is empty, return all types -> no filter - if ((count($types) == 0) || in_array($relationType, $types)) { - $name = $modelGenerator->generateRelationName( - [$relation], - $model->getTableSchema(), - substr($method->name, 3), - $relation->multiple - ); + if ((count($types) === 0) || in_array($relationType, $types, true)) { + if ($this->disablePluralization) { + $name = str_replace('get','', $method->name); + } else { + $name = $modelGenerator->generateRelationName( + [$relation], + $model->getTableSchema(), + substr($method->name, 3), + $relation->multiple + ); + } $stack[$name] = $relation; } } @@ -146,6 +152,7 @@ public function getColumnByAttribute($attribute, $model = null) $model = $this; } + // omit schema for NOSQL models if (method_exists($model,'getTableSchema') && $model->getTableSchema()) { return $model->getTableSchema()->getColumn($attribute); @@ -164,12 +171,12 @@ public function getRelationByColumn($model, $column, $types = ['belongs_to', 'ma $relations = $this->getModelRelations($model, $types); foreach ($relations as $relation) { // TODO: check multiple link(s) - if ($relation->link && reset($relation->link) == $column->name) { + if ($relation->link && reset($relation->link) === $column->name) { return $relation; } } - return; + return null; } public function createRelationRoute($relation, $action) @@ -179,7 +186,6 @@ public function createRelationRoute($relation, $action) '-', true ).'/'.$action; - return $route; } diff --git a/src/generators/crud/callbacks/devgroup/Jsoneditor.php b/src/generators/crud/callbacks/devgroup/Jsoneditor.php index 3568674e..c0d3ace4 100644 --- a/src/generators/crud/callbacks/devgroup/Jsoneditor.php +++ b/src/generators/crud/callbacks/devgroup/Jsoneditor.php @@ -12,8 +12,8 @@ class Jsoneditor public static function field() { return function ($attribute) { - $collapse = Collapse::className(); - $editor = \devgroup\jsoneditor\Jsoneditor::className(); + $collapse = Collapse::class; + $editor = \devgroup\jsoneditor\Jsoneditor::class; return <<'. @@ -39,7 +39,7 @@ public static function field() public static function attribute() { return function ($attribute, $generator) { - $formattter = StringFormatter::className(); + $formattter = StringFormatter::class; $method = __METHOD__; return <<field(\$model, 'request_param')->widget( - {$input}::className(), + {$input}::class, [ // single query fetch to render the tree 'query' => {$tree}::find()->addOrderBy('root, lft'), diff --git a/src/generators/crud/default/access_definition.php b/src/generators/crud/default/access_definition.php index e7b10baf..2b1dcaa9 100644 --- a/src/generators/crud/default/access_definition.php +++ b/src/generators/crud/default/access_definition.php @@ -13,7 +13,7 @@ /** * permissions - create name and descriptions */ -$permisions = []; +$permissions = []; foreach ($actions as $k => $action){ $name = $this->getModuleId() . '_' . $this->getControllerID() @@ -21,7 +21,7 @@ $description = $this->getModuleId() . '/' . $this->getControllerID() . '/' . $action; - $permisions[$action] = [ + $permissions[$action] = [ 'name' => $name, 'description' => $description, ]; @@ -48,6 +48,6 @@ } return [ - 'permisions' => $permisions, + 'permissions' => $permissions, 'roles' => $roles, -]; \ No newline at end of file +]; diff --git a/src/generators/crud/default/controller-extended.php b/src/generators/crud/default/controller-extended.php index 7c9ec5fb..7c565c56 100644 --- a/src/generators/crud/default/controller-extended.php +++ b/src/generators/crud/default/controller-extended.php @@ -7,10 +7,12 @@ namespace controllerClass, '\\')) ?>; +use controllerNs) ? '\\'.$generator->controllerNs.'\\' : '', '\\') .'base\\'.$controllerClassName?> as Base; + /** -* This is the class for controller "". -*/ -class extends controllerNs) ? '\\'.$generator->controllerNs.'\\' : '') .'base\\'.$controllerClassName."\n" ?> + * This is the class for controller "". + */ +class extends Base { } diff --git a/src/generators/crud/default/controller-rest.php b/src/generators/crud/default/controller-rest.php index 4fe19400..24fecce0 100644 --- a/src/generators/crud/default/controller-rest.php +++ b/src/generators/crud/default/controller-rest.php @@ -2,41 +2,54 @@ /** * Customizable controller class. */ + +use yii\helpers\StringHelper; + +$modelClass = StringHelper::basename($generator->modelClass); echo " namespace controllerNs ?>\api; /** -* This is the class for REST controller "". -*/ + * This is the class for REST controller "". + */ +use modelClass ?>; +accessFilter): ?> use yii\filters\AccessControl; use yii\helpers\ArrayHelper; + +use yii\rest\ActiveController; +accessFilter): ?> +use Yii; + -class extends \yii\rest\ActiveController +class extends ActiveController { -public $modelClass = 'modelClass ?>'; + public $modelClass = ::class; accessFilter): ?> + /** - * @inheritdoc - */ + * @inheritdoc + */ public function behaviors() { - return ArrayHelper::merge( - parent::behaviors(), - [ - 'access' => [ - 'class' => AccessControl::className(), - 'rules' => [ - [ - 'allow' => true, - 'matchCallback' => function ($rule, $action) {return \Yii::$app->user->can($this->module->id . '_' . $this->id . '_' . $action->id, ['route' => true]);}, - ] - ] - ] - ] - ); + return ArrayHelper::merge(parent::behaviors(), + [ + 'access' => [ + 'class' => AccessControl::class, + 'rules' => [ + [ + 'allow' => true, + 'matchCallback' => function ($rule, $action) { + return Yii::$app->user->can($this->module->id . '_' . $this->id . '_' . $action->id, ['route' => true]); + } + ] + ] + ] + ] + ); } } diff --git a/src/generators/crud/default/controller.php b/src/generators/crud/default/controller.php index d8c965ef..9b6a25a0 100644 --- a/src/generators/crud/default/controller.php +++ b/src/generators/crud/default/controller.php @@ -2,11 +2,12 @@ use yii\helpers\StringHelper; -/* +/** * This is the template for generating a CRUD controller class file. * * @var yii\web\View $this * @var schmunk42\giiant\generators\crud\Generator $generator + * @var array $accessDefinitions */ $controllerClass = StringHelper::basename($generator->controllerClass); @@ -37,208 +38,192 @@ use modelClass, '\\') ?>; - use searchModelClass, '\\' ) ?> as ; -use baseControllerClass, '\\') ?>; -use yii\web\HttpException; -use yii\helpers\Url; +accessFilter): ?> use yii\filters\AccessControl; -use dmstr\bootstrap\Tabs; +use yii\helpers\ArrayHelper; + +use yii\base\InvalidConfigException; +use yii\helpers\Url; +use baseControllerClass, '\\') ?>; +use yii\web\NotFoundHttpException; +use yii\web\Request; +use yii\web\Response; +use Yii; /** -* implements the CRUD actions for model. -*/ + * implements the CRUD actions for model. + * + * @property-read Request $request + */ class extends baseControllerClass)."\n" ?> { - baseTraits; if ($traits) { echo "use {$traits};"; } -?> -/** -* @var boolean whether to enable CSRF validation for the actions in this controller. -* CSRF validation is enabled only when both this property and [[Request::enableCsrfValidation]] are true. -*/ -public $enableCsrfValidation = false; +?> accessFilter): ?> /** - * @inheritdoc - */ + * @inheritdoc + */ public function behaviors() { - return [ - 'access' => [ - 'class' => AccessControl::className(), - 'rules' => [ - $actions){ -?> - [ - 'allow' => true, - 'actions' => [''], - 'roles' => [''], - ], - - ], - ], - ]; + return ArrayHelper::merge(parent::behaviors(), + [ + 'access' => [ + 'class' => AccessControl::class, + 'rules' => [ + $actions): ?> + [ + 'allow' => true, + 'actions' => [''], + 'roles' => [''] + ], + + ] + ] + ]); } -/** -* Lists all models. -* @return mixed -*/ -public function actionIndex() -{ - - $searchModel = new ; - $dataProvider = $searchModel->search($_GET); - - $dataProvider = new \yii\data\ActiveDataProvider([ - 'query' => ::find(), - ]); - - -Tabs::clearLocalStorage(); - -Url::remember(); -\Yii::$app->session['__crudReturnUrl'] = null; - -return $this->render('index', [ -'dataProvider' => $dataProvider, - + /** + * Lists all models. + * + * @throws InvalidConfigException + * @return string + */ + public function actionIndex() + { + + $searchModel = Yii::createObject(::class); + $dataProvider = $searchModel->search($this->request->get()); + + $dataProvider = new ActiveDataProvider([ + 'query' => ::find(), + ]); + + + return $this->render('index', [ + 'dataProvider' => $dataProvider, + 'searchModel' => $searchModel, - + ]); -} - -/** -* Displays a single model. -* -* -* @return mixed -*/ -public function actionView() -{ -\Yii::$app->session['__crudReturnUrl'] = Url::previous(); -Url::remember(); -Tabs::rememberActiveState(); - -return $this->render('view', [ -'model' => $this->findModel(), -]); -} - -/** -* Creates a new model. -* If creation is successful, the browser will be redirected to the 'view' page. -* @return mixed -*/ -public function actionCreate() -{ -$model = new ; + } -try { -if ($model->load($_POST) && $model->save()) { -return $this->redirect(['view', ]); -} elseif (!\Yii::$app->request->isPost) { -$model->load($_GET); -} -} catch (\Exception $e) { -$msg = (isset($e->errorInfo[2]))?$e->errorInfo[2]:$e->getMessage(); -$model->addError('_exception', $msg); -} -return $this->render('create', ['model' => $model]); -} + /** + * Displays a single model. + * + * + * + * @throws NotFoundHttpException + * @return string + */ + public function actionView() + { + return $this->render('view', ['model' => $this->findModel()]); -/** -* Updates an existing model. -* If update is successful, the browser will be redirected to the 'view' page. -* -* @return mixed -*/ -public function actionUpdate() -{ -$model = $this->findModel(); + } -if ($model->load($_POST) && $model->save()) { -return $this->redirect(Url::previous()); -} else { -return $this->render('update', [ -'model' => $model, -]); -} -} + /** + * Creates a new model. + * If creation is successful, the browser will be redirected to the 'view' page. + * + * @throws yii\base\InvalidConfigException + * @return string|Response + */ + public function actionCreate() + { + $model = Yii::createObject(::class); + try { + if ($model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', ]); + } + if (!Yii::$app->request->isPost) { + $model->load($this->request->get()); + } + } catch (\Exception $e) { + $model->addError('_exception', $e->errorInfo[2] ?? $e->getMessage()); + } + return $this->render('create', ['model' => $model]); + } -/** -* Deletes an existing model. -* If deletion is successful, the browser will be redirected to the 'index' page. -* -* @return mixed -*/ -public function actionDelete() -{ -try { -$this->findModel()->delete(); -} catch (\Exception $e) { -$msg = (isset($e->errorInfo[2]))?$e->errorInfo[2]:$e->getMessage(); -\Yii::$app->getSession()->addFlash('error', $msg); -return $this->redirect(Url::previous()); -} + /** + * Updates an existing model. + * If update is successful, the browser will be redirected to the 'view' page. + * + * + * + * @throws NotFoundHttpException + * @return string|Response + */ + public function actionUpdate() + { + $model = $this->findModel(); + if ($model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', ]); + } + return $this->render('update', ['model' => $model]); + } -// TODO: improve detection -$isPivot = strstr('',','); -if ($isPivot == true) { -return $this->redirect(Url::previous()); -} elseif (isset(\Yii::$app->session['__crudReturnUrl']) && \Yii::$app->session['__crudReturnUrl'] != '/') { -Url::remember(null); -$url = \Yii::$app->session['__crudReturnUrl']; -\Yii::$app->session['__crudReturnUrl'] = null; + /** + * Deletes an existing model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * + * + * + * @throws \Throwable + * @return Response + */ + public function actionDelete() + { + try { + $this->findModel()->delete(); + } catch (\Exception $e) { + Yii::$app->getSession()->addFlash('error', $e->errorInfo[2] ?? $e->getMessage()); + } -return $this->redirect($url); -} else { -return $this->redirect(['index']); -} -} + return $this->redirect(['index']); + } -/** -* Finds the model based on its primary key value. -* If the model is not found, a 404 HTTP exception will be thrown. -* -* @return the loaded model -* @throws HttpException if the model cannot be found -*/ -protected function findModel() -{ - \$$pk"; + /** + * Finds the model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * + * + * + * @throws NotFoundHttpException if the model cannot be found + * @return the loaded model + */ + protected function findModel() + { + \$$pk"; + } + $condition = '['.implode(', ', $condition).']'; + } + ?> + $model = ::findOne(); + if ($model !== null) { + return $model; + } + throw new NotFoundHttpException(generateString('The requested page does not exist.')?>); } - $condition = '['.implode(', ', $condition).']'; -} -?> -if (($model = ::findOne()) !== null) { -return $model; -} else { -throw new HttpException(404, 'The requested page does not exist.'); -} -} } diff --git a/src/generators/crud/default/migration_access.php b/src/generators/crud/default/migration_access.php index 3e708e85..0a841eea 100644 --- a/src/generators/crud/default/migration_access.php +++ b/src/generators/crud/default/migration_access.php @@ -13,26 +13,26 @@ class migrationClass?> extends Migration /** * @var array controller all actions */ - public $permisions = var_export54($accessDefinitions['permisions'],' ')?>; + public $permissions = var_export54($accessDefinitions['permissions'],' ')?>; /** - * @var array roles and maping to actions/permisions + * @var array roles and maping to actions/permissions */ public $roles = var_export54($accessDefinitions['roles'],' ')?>; public function up() { - $permisions = []; + $permissions = []; $auth = \Yii::$app->authManager; /** - * create permisions for each controller action + * create permissions for each controller action */ - foreach ($this->permisions as $action => $permission) { - $permisions[$action] = $auth->createPermission($permission['name']); - $permisions[$action]->description = $permission['description']; - $auth->add($permisions[$action]); + foreach ($this->permissions as $action => $permission) { + $permissions[$action] = $auth->createPermission($permission['name']); + $permissions[$action]->description = $permission['description']; + $auth->add($permissions[$action]); } /** @@ -46,7 +46,7 @@ public function up() * to role assign permissions */ foreach ($actions as $action) { - $auth->addChild($role, $permisions[$action]); + $auth->addChild($role, $permissions[$action]); } } } @@ -59,7 +59,7 @@ public function down() { $auth->remove($role); } - foreach ($this->permisions as $permission) { + foreach ($this->permissions as $permission) { $authItem = $auth->createPermission($permission['name']); $auth->remove($authItem); } diff --git a/src/generators/crud/default/search.php b/src/generators/crud/default/search.php index 441df99d..25aa1f04 100644 --- a/src/generators/crud/default/search.php +++ b/src/generators/crud/default/search.php @@ -2,10 +2,13 @@ /** * This is the template for generating CRUD search class of the specified model. */ + +use yii\helpers\Inflector; use yii\helpers\StringHelper; -/* @var $this yii\web\View */ -/* @var $generator yii\gii\generators\crud\Generator */ +/* @var $this yii\web\View + * @var $generator schmunk42\giiant\generators\crud\Generator + */ $modelClass = StringHelper::basename($generator->modelClass); $searchModelClass = StringHelper::basename($generator->searchModelClass); @@ -61,7 +64,12 @@ public function scenarios() */ public function search($params) { -$query = ::find(); +$query = ::find(); + +getHasTranslationRelation()): ?> + $query->leftJoin(translationModelClass?>::tableName(),::tableName() . '.id = ' . translationModelClass?>::tableName() . '._id'); + + $dataProvider = new ActiveDataProvider([ 'query' => $query, @@ -74,9 +82,12 @@ public function search($params) // $query->where('0=1'); return $dataProvider; } +getHasTranslationRelation()): ?> + $query->groupBy(::tableName() . '.id'); + return $dataProvider; } -} \ No newline at end of file +} diff --git a/src/generators/crud/default/views/_form-fields.php b/src/generators/crud/default/views/_form-fields.php new file mode 100644 index 00000000..77927217 --- /dev/null +++ b/src/generators/crud/default/views/_form-fields.php @@ -0,0 +1,35 @@ + +/** + * @var yii\web\View $this + * @var modelClass, '\\') ?> $model + * @var yii\widgets\ActiveForm $form + */ +?> +\n"; + $prepend = $generator->prependActiveField($attribute, $model); + $field = $generator->activeField($attribute, $model); + $append = $generator->appendActiveField($attribute, $model); + + if ($prepend) { + echo $prepend; + } + if ($field) { + echo "'; + } + if ($append) { + echo $append; + } +} diff --git a/src/generators/crud/default/views/_form.php b/src/generators/crud/default/views/_form.php index e8b2be29..92116fd1 100644 --- a/src/generators/crud/default/views/_form.php +++ b/src/generators/crud/default/views/_form.php @@ -1,31 +1,21 @@ modelClass(); -$model->setScenario('crud'); -$safeAttributes = $model->safeAttributes(); -if (empty($safeAttributes)) { - $model->setScenario('default'); - $safeAttributes = $model->safeAttributes(); -} -if (empty($safeAttributes)) { - $safeAttributes = $model->getTableSchema()->columnNames; -} - echo " use yii\helpers\Html; use yii\bootstrap\ActiveForm; -use \dmstr\bootstrap\Tabs; +use yii\bootstrap\Tabs; use yii\helpers\StringHelper; /** @@ -51,7 +41,6 @@ 'template' => "{label}\n{beginWrapper}\n{input}\n{hint}\n{error}\n{endWrapper}", 'horizontalCssClasses' => [ 'label' => 'col-sm-2', - #'offset' => 'col-sm-offset-4', 'wrapper' => 'col-sm-8', 'error' => '', 'hint' => '', @@ -61,51 +50,18 @@ ); ?> -
- beginBlock('main'); ?>\n"; ?> - -

- "; - $prepend = $generator->prependActiveField($attribute, $model); - $field = $generator->activeField($attribute, $model); - $append = $generator->appendActiveField($attribute, $model); - - if ($prepend) { - echo "\n\t\t\t".$prepend; - } - if ($field) { - echo "\n\t\t\t'; - } - if ($append) { - echo "\n\t\t\t".$append; - } - } - ?> - -

- endBlock(); ?>'; ?> - Yii::t('$generator->modelMessageCategory', '$label'), - 'content' => \$this->blocks['main'], - 'active' => true, -], -EOS; - ?> - - generateString(Inflector::camel2words(StringHelper::basename($model::class))); + echo " false, 'items' => [ - $items + [ + 'label' => $label, + 'content' => \$this->render('_form-fields', ['form' => \$form, 'model' => \$model]), + 'active' => true, + ] ] ] ); @@ -128,7 +84,5 @@ ActiveForm::end(); ?> -
- diff --git a/src/generators/crud/default/views/_search.php b/src/generators/crud/default/views/_search.php index fcc878f6..c827c4ed 100644 --- a/src/generators/crud/default/views/_search.php +++ b/src/generators/crud/default/views/_search.php @@ -3,7 +3,7 @@ use yii\helpers\Inflector; use yii\helpers\StringHelper; -/* +/** * @var yii\web\View $this * @var yii\gii\generators\crud\Generator $generator */ @@ -32,7 +32,7 @@ $count = 0; foreach ($generator->getTableSchema()->getColumnNames() as $attribute) { if (++$count < 6) { - echo "\t\tgenerateActiveSearchField($attribute)." ?>\n\n"; + echo "\t\tgenerateActiveSearchField($attribute)." ?>\n\n"; } else { echo "\t\tgenerateActiveSearchField($attribute)." ?>\n\n"; } diff --git a/src/generators/crud/default/views/create.php b/src/generators/crud/default/views/create.php index fce4e1ea..40d44f29 100644 --- a/src/generators/crud/default/views/create.php +++ b/src/generators/crud/default/views/create.php @@ -3,7 +3,7 @@ use yii\helpers\Inflector; use yii\helpers\StringHelper; -/* +/** * @var yii\web\View $this * @var yii\gii\generators\crud\Generator $generator */ @@ -11,7 +11,7 @@ /** @var \yii\db\ActiveRecord $model */ $model = new $generator->modelClass(); $model->setScenario('crud'); -$modelName = Inflector::camel2words(StringHelper::basename($model::className())); +$modelName = Inflector::camel2words(StringHelper::basename($model::class)); echo "generateUrlParams(); $nameAttribute = $generator->getNameAttribute(); +$permissions = $accessDefinitions['permissions']; /** @var \yii\db\ActiveRecord $model */ $model = new $generator->modelClass(); -$model->setScenario('crud'); +if (array_key_exists('crud-list', $model->scenarios())) { + $model->setScenario('crud-list'); +} else { + $model->setScenario('crud'); +} + -$baseName = StringHelper::basename($model::className()); +$baseName = StringHelper::basename($model::class); $modelName = Inflector::camel2words($baseName); $safeAttributes = $model->safeAttributes(); if (empty($safeAttributes)) { - /** @var \yii\db\ActiveRecord $model */ - $model = new $generator->modelClass(); + $model->setScenario('default'); $safeAttributes = $model->safeAttributes(); - if (empty($safeAttributes)) { - $safeAttributes = $model->getTableSchema()->columnNames; - } +} +if (empty($safeAttributes)) { + $safeAttributes = $model::getTableSchema()->columnNames; } echo " /** -* create action column template depending acces rights +* create action column template depending on user's access rights */ $actionColumnTemplates = []; -if (\Yii::$app->user->can('', ['route' => true])) { +if (\Yii::$app->user->can('', ['route' => true])) { $actionColumnTemplates[] = '{view}'; } -if (\Yii::$app->user->can('', ['route' => true])) { +if (\Yii::$app->user->can('', ['route' => true])) { $actionColumnTemplates[] = '{update}'; } -if (\Yii::$app->user->can('', ['route' => true])) { +if (\Yii::$app->user->can('', ['route' => true])) { $actionColumnTemplates[] = '{delete}'; } modelClass), '-', true) ?>-index"> - indexWidgetType === 'grid' ? '// ' : '') ?> - searchModelClass !== ''): ?> - echo $this->render('_search', ['model' =>$searchModel]); - - ?> + indexWidgetType !== 'grid' && $generator->searchModelClass !== '') { + echo "render('_search', ['model' => \$searchModel]); ?>"; + } ?> indexWidgetType === 'grid'): ?> - 'pjax-main', 'enableReplaceState'=> false, 'linkSelector'=>'#pjax-main ul.pagination a, th a', 'clientOptions' => ['pjax:success'=>'function(){alert(\"yo\")}']]) ?>\n"; ?> + 'pjax-main', 'enableReplaceState'=> false, 'linkSelector'=>'#pjax-main ul.pagination a, th a']) ?>\n"; ?>

- modelMessageCategory}.plural', '{$modelName}') ?>\n" ?> - - messageCategory}', 'List') ?>\n" ?> - + generateString($modelName) . "?>\n" ?> + generateString('List') . "?>\n" ?>

accessFilter){ echo " -if(\Yii::$app->user->can('', ['route' => true])){ +if(\Yii::$app->user->can('', ['route' => true])){ \n" ?>
Html::a(' ' . generateString( - 'New' + 'New ' . $modelName ) ?>, ['create'], ['class' => 'btn btn-success']) ?>
Html::a(' ' . generateString( - 'New' + 'New ' . $modelName ) ?>, ['create'], ['class' => 'btn btn-success']) ?>
createRelationRoute($relation, 'index'); - $label = Inflector::titleize(StringHelper::basename($relation->modelClass), '-', true); + $label = Inflector::titleize(StringHelper::basename($relation->modelClass), '-'); + $i18nMessageLabel = $generator->generateString($label); $items .= << ['{$route}'], - 'label' => ' ' . Yii::t('$generator->modelMessageCategory', '$label'), + 'url' => ['$route'], + 'label' => ' ' . $i18nMessageLabel, ], PHP; @@ -184,20 +185,19 @@
- GridView::widget([ + GridView::widget([ 'dataProvider' => $dataProvider, 'pager' => [ - 'class' => yii\widgets\LinkPager::className(), + 'class' => yii\widgets\LinkPager::class, 'firstPageLabel' => generateString('First') ?>, 'lastPageLabel' => generateString('Last').",\n" ?> ], searchModelClass !== ''): ?> 'filterModel' => $searchModel, - 'tableOptions' => ['class' => 'table table-striped table-bordered table-hover'], - 'headerRowOptions' => ['class'=>'x'], 'columns' => [ generateString('View'); $actionButtonColumn = << '{$generator->actionButtonClass}', @@ -205,8 +205,8 @@ 'buttons' => [ 'view' => function (\$url, \$model, \$key) { \$options = [ - 'title' => Yii::t('{$generator->messageCategory}', 'View'), - 'aria-label' => Yii::t('{$generator->messageCategory}', 'View'), + 'title' => $i18nMessageView, + 'aria-label' => $i18nMessageView, 'data-pjax' => '0', ]; return Html::a('', \$url, \$options); @@ -224,25 +224,25 @@ $count = 0; // action buttons first - if ($generator->actionButtonColumnPosition != 'right') { + if ($generator->actionButtonColumnPosition !== 'right') { echo $actionButtonColumn; echo "\n"; // code-formatting } + foreach ($safeAttributes as $attribute) { - $format = trim($generator->columnFormat($attribute, $model)); - if ($format == false) { + $format = trim((string)$generator->columnFormat($attribute, $model)); + if (empty($format)) { continue; } - if (++$count < $generator->gridMaxColumns) { + if (++$count <= $generator->gridMaxColumns) { echo "\t\t\t" . str_replace("\n", "\n\t\t\t", $format) . ",\n"; } else { echo "\t\t\t/*" . str_replace("\n", "\n\t\t\t", $format) . ",*/\n"; } } - ?> - actionButtonColumnPosition == 'right') { + actionButtonColumnPosition === 'right') { echo $actionButtonColumn; echo "\n"; // code-formatting } ?> @@ -260,7 +260,7 @@ ListView::widget([ 'dataProvider' => $dataProvider, 'itemOptions' => ['class' => 'item'], - 'itemView' => function ($model, $key, $index, $widget) { + 'itemView' => function ($model) { return Html::a(Html::encode($model->), ['view', ]); }, ]); ?> diff --git a/src/generators/crud/default/views/update.php b/src/generators/crud/default/views/update.php index 3d52aa27..2a24d086 100644 --- a/src/generators/crud/default/views/update.php +++ b/src/generators/crud/default/views/update.php @@ -3,7 +3,7 @@ use yii\helpers\Inflector; use yii\helpers\StringHelper; -/* +/** * @var yii\web\View $this * @var yii\gii\generators\crud\Generator $generator */ @@ -11,8 +11,8 @@ $urlParams = $generator->generateUrlParams(); $model = new $generator->modelClass(); $model->setScenario('crud'); -$className = $model::className(); -$modelName = Inflector::camel2words(StringHelper::basename($model::className())); +$className = $model::class; +$modelName = Inflector::camel2words(StringHelper::basename($model::class)); echo " diff --git a/src/generators/crud/default/views/view.php b/src/generators/crud/default/views/view.php index cf6c36df..45737a0d 100644 --- a/src/generators/crud/default/views/view.php +++ b/src/generators/crud/default/views/view.php @@ -1,31 +1,33 @@ modelClass(); -$model->setScenario('crud'); +if (array_key_exists('crud-view', $model->scenarios())) { + $model->setScenario('crud-view'); +} else { + $model->setScenario('crud'); +} $safeAttributes = $model->safeAttributes(); if (empty($safeAttributes)) { $model->setScenario('default'); $safeAttributes = $model->safeAttributes(); } if (empty($safeAttributes)) { - $safeAttributes = $model->getTableSchema()->columnNames; + $safeAttributes = $model::getTableSchema()->columnNames; } -$modelName = Inflector::camel2words(StringHelper::basename($model::className())); -$className = $model::className(); +$className = $model::class; +$modelName = Inflector::camel2words(StringHelper::basename($className)); $urlParams = $generator->generateUrlParams(); +$permissions = $accessDefinitions['permissions']; echo " @@ -35,60 +37,79 @@ use yii\grid\GridView; use yii\widgets\DetailView; use yii\widgets\Pjax; -use dmstr\bootstrap\Tabs; +use yii\bootstrap\Tabs; /** * @var yii\web\View $this * @var modelClass, '\\') ?> $model */ -$copyParams = $model->attributes; $this->title = Yii::t('modelMessageCategory ?>', ''); $this->params['breadcrumbs'][] = ['label' => Yii::t('modelMessageCategory ?>.plural', ''), 'url' => ['index']]; -$this->params['breadcrumbs'][] = ['label' => (string)$model->getModelNameAttribute($model)?>, 'url' => ['view', ]]; +$this->params['breadcrumbs'][] = ['label' => (string)$model->, 'url' => ['view', ]]; $this->params['breadcrumbs'][] = generateString('View') ?>; ?>
- - session->getFlash('deleteError') !== null) : ?> - - - session->getFlash('deleteError') ?> - - " ?> - -

- '.$generator->getModelNameAttribute($generator->modelClass).") ?>\n" ?> - - modelMessageCategory}', '{$modelName}') ?>\n" ?> - + ' . $generator::getModelNameAttribute($generator->modelClass) . ") ?>\n" ?> + generateString($modelName) . ' ?>' ?>

-
- Html::a( - ' ' . generateString('Edit') ?>, + + accessFilter) { + echo 'getUser()->can(\'' . $permissions['update']['name'] . '\')): ?>'; + } + ?> + Html::a( + ' ' . generateString('Edit ' . $modelName) ?>, [ 'update', ], ['class' => 'btn btn-info']) - ?> - - Html::a( - ' ' . generateString('Copy') ?>, - ['create', , 'modelClass) ?>'=>$copyParams], + ?> + accessFilter) { + echo ''; + } + ?> + + enableCopy): ?> + accessFilter) { + echo 'getUser()->can(\'' . $permissions['update']['name'] . '\')): ?>'; + } + ?> + Html::a( + ' ' . generateString('Copy ' . $modelName) ?>, + ['create', , 'modelClass) ?>'=> $model->hasMethod('getCopyParams') ? $model->getCopyParams() : $model->attributes], ['class' => 'btn btn-success']) - ?> - - Html::a( - ' ' . generateString('New') ?>, + ?> + accessFilter) { + echo ''; + } + ?> + + + accessFilter) { + echo 'getUser()->can(\'' . $permissions['create']['name'] . '\')): ?>'; + } + ?> + Html::a( + ' ' . generateString('New ' . $modelName) ?>, ['create'], ['class' => 'btn btn-success']) - ?> + ?> + accessFilter) { + echo ''; + } + ?>
@@ -106,7 +127,7 @@ partialView('detail_prepend', $model); ?> - DetailView::widget([ + DetailView::widget([ 'model' => $model, 'attributes' => [ ], ]); - ?> + ?> partialView('detail_append', $model); ?>
- Html::a(' ' . generateString( - 'Delete' + accessFilter) { + echo 'getUser()->can(\'' . $permissions['delete']['name'] . '\')): ?>'; + } + ?> + Html::a(' ' + . generateString( + 'Delete ' . $modelName ) ?>, ['delete', ], [ 'class' => 'btn btn-danger', 'data-confirm' => '' . generateString('Are you sure to delete this item?') ?> . '', 'data-method' => 'post', ]); - ?> + ?> + accessFilter) { + echo ''; + } + ?> endBlock(); ?>\n\n"; ?> '# '.Html::encode(\$model->{$model->primaryKey()[0]}).'', + 'label' => '' . \Yii::t('{$generator->messageCategory}', '# {primaryKey}', ['primaryKey' => Html::encode(\$model->{$model->primaryKey()[0]})]) . '', 'content' => \$this->blocks['{$generator->modelClass}'], 'active' => true, ], @@ -156,57 +188,60 @@ echo "\nbeginBlock('$name'); ?>\n"; $showAllRecords = false; - if ($relation->via !== null) { - $pivotName = Inflector::pluralize($generator->getModelByTableName($relation->via->from[0])); - $pivotRelation = $model->{'get'.$pivotName}(); + $modelName = $generator->getModelByTableName($relation->via->from[0]); + if ($generator->disablePluralization) { + $pivotName = $name; + } else { + $pivotName = Inflector::pluralize($modelName); + } + $label = Inflector::camel2words($pivotName); + $pivotRelation = $model->{'get' . $pivotName}(); $pivotPk = key($pivotRelation->link); $addButton = " ' . ".$generator->generateString('Attach')." . ' ". - Inflector::singularize(Inflector::camel2words($name)). - "', ['".$generator->createRelationRoute($pivotRelation, 'create')."', '". - Inflector::singularize($pivotName)."'=>['".key( + ' ' . " . $generator->generateString('Attach ' . $label) . + ", ['" . $generator->createRelationRoute($pivotRelation, 'create') . "', '" . + $modelName . "'=>['" . key( $pivotRelation->link - )."'=>\$model->{$model->primaryKey()[0]}]], + ) . "'=>\$model->{$model->primaryKey()[0]}]], ['class'=>'btn btn-info btn-xs'] ) ?>\n"; } else { $addButton = ''; + $label = Inflector::camel2words($name); } // relation list, add, create buttons - echo "
\n
\n"; + echo "
\n"; echo " ' . ".$generator->generateString('List All')." . ' ". - Inflector::camel2words($name)."', - ['".$generator->createRelationRoute($relation, 'index')."'], + ' ' . " . $generator->generateString('List All ' . $label) . ", + ['" . $generator->createRelationRoute($relation, 'index') . "'], ['class'=>'btn text-muted btn-xs'] ) ?>\n"; // TODO: support multiple PKs // pivot check if ($relation->via !== null) { - $url = "['".$generator->createRelationRoute($relation, 'create')."']"; + $url = "['" . $generator->createRelationRoute($relation, 'create') . "']"; } else { - $url = "['".$generator->createRelationRoute($relation, 'create')."', '". + $url = "['" . $generator->createRelationRoute($relation, 'create') . "', '" . Inflector::id2camel($generator->generateRelationTo($relation), '-', - true)."' => ['".key($relation->link)."' => \$model->".$model->primaryKey()[0]."]]"; + true) . "' => ['" . key($relation->link) . "' => \$model->" . $model->primaryKey()[0] . "]]"; } - echo " ' . ".$generator->generateString('New')." . ' ". - Inflector::camel2words($name)."', + echo " ' . " . $generator->generateString('New ' . $label) . ", {$url}, ['class'=>'btn btn-success btn-xs'] ); ?>\n"; echo $addButton; - echo "
\n
\n"; #
\n"; + echo "
\n
"; // render pivot grid if ($relation->via !== null) { $pjaxId = "pjax-{$pivotName}"; @@ -223,18 +258,17 @@ // render relation grid if (!empty($output)): echo "'pjax-{$name}', 'enableReplaceState'=> false, 'linkSelector'=>'#pjax-{$name} ul.pagination a, th a']) ?>\n"; - echo "\n"; + echo "\n"; echo "\n"; endif; echo "endBlock() ?>\n\n"; - // build tab items - $label = Inflector::camel2words($name); + $itemLabel = $generator->generateString($label); $items .= << \$this->blocks['$name'], - 'label' => '$label '. \$model->get{$name}()->count() . '', + 'label' => '' . $itemLabel .' '. \$model->get{$name}()->count() . '', 'active' => false, ],\n EOS; diff --git a/src/generators/crud/editable/access_definition.php b/src/generators/crud/editable/access_definition.php index 2c184292..2280c9af 100644 --- a/src/generators/crud/editable/access_definition.php +++ b/src/generators/crud/editable/access_definition.php @@ -22,7 +22,7 @@ /** * permissions - create name and descriptions */ -$permisions = []; +$permissions = []; foreach ($actions as $k => $action){ $name = $this->getModuleId() . '_' . $this->getControllerID() @@ -30,7 +30,7 @@ $description = $this->getModuleId() . '/' . $this->getControllerID() . '/' . $action; - $permisions[$action] = [ + $permissions[$action] = [ 'name' => $name, 'description' => $description, ]; @@ -76,6 +76,6 @@ } return [ - 'permisions' => $permisions, + 'permissions' => $permissions, 'roles' => $roles, -]; \ No newline at end of file +]; diff --git a/src/generators/crud/editable/controller-rest.php b/src/generators/crud/editable/controller-rest.php index 4fe19400..5a355c26 100644 --- a/src/generators/crud/editable/controller-rest.php +++ b/src/generators/crud/editable/controller-rest.php @@ -27,7 +27,7 @@ public function behaviors() parent::behaviors(), [ 'access' => [ - 'class' => AccessControl::className(), + 'class' => AccessControl::class, 'rules' => [ [ 'allow' => true, diff --git a/src/generators/crud/editable/controller.php b/src/generators/crud/editable/controller.php index 02ddd4e0..b93eceb8 100644 --- a/src/generators/crud/editable/controller.php +++ b/src/generators/crud/editable/controller.php @@ -62,9 +62,9 @@ public function behaviors() { return [ 'access' => [ - 'class' => AccessControl::className(), + 'class' => AccessControl::class, 'rules' => [ - $actions){ ?> [ @@ -74,7 +74,7 @@ public function behaviors() ], 'roles' => [''], ], - ], ], @@ -85,12 +85,12 @@ public function behaviors() public function actions() { return [ 'editable-column-update' => [ - 'class' => EditableColumnAction::className(), // action class name - 'modelClass' => ::className(), + 'class' => EditableColumnAction::class, // action class name + 'modelClass' => ::class, ], ]; - } - + } + /** * Lists all models. * @return mixed @@ -100,14 +100,14 @@ public function actionIndex() $searchModel = new ; - $dataProvider = $searchModel->search($_GET); -search($this->request->get()); + $dataProvider = new ActiveDataProvider([ 'query' => ::find(), ]); - Url::remember(); @@ -139,36 +139,36 @@ public function actionView() /** * Creates a new model. - * If creation is successful, the browser will be redirected + * If creation is successful, the browser will be redirected * to the 'view' page or back, if parameter $goBack is true. * @return mixed */ public function actionCreate() { $model = new ; - $model->load($_GET); + $model->load($this->request->get()); $relAttributes = $model->attributes; - + try { if ($model->load($_POST) && $model->save()) { if($relAttributes){ return $this->goBack(); - } + } return $this->redirect(['view', ]); } elseif (!\Yii::$app->request->isPost) { - $model->load($_GET); + $model->load($this->request->get()); } } catch (\Exception $e) { $msg = (isset($e->errorInfo[2]))?$e->errorInfo[2]:$e->getMessage(); $model->addError('_exception', $msg); } - + return $this->render('create', [ 'model' => $model, - 'relAttributes' => $relAttributes, + 'relAttributes' => $relAttributes, ]); } - + /** * Add a new TestContacts record for relation grid and redirect back. * @return mixed @@ -176,12 +176,12 @@ public function actionCreate() public function actionCreateForRel() { $model = new ; - $model->load($_GET); + $model->load($this->request->get()); $relAttributes = $model->attributes; $model->save(); return $this->goBack(); } - + /** * Updates an existing model. * If update is successful, the browser will be redirected to the 'view' page. @@ -191,9 +191,9 @@ public function actionCreateForRel() public function actionUpdate() { $model = new ; - $model->load($_GET); + $model->load($this->request->get()); $relAttributes = $model->attributes; - + $model = $this->findModel(); if ($model->load($_POST) && $model->save()) { @@ -201,7 +201,7 @@ public function actionUpdate() } else { return $this->render('update', [ 'model' => $model, - 'relAttributes' => $relAttributes + 'relAttributes' => $relAttributes ]); } } @@ -223,12 +223,12 @@ public function actionDelete() } $model = new ; - $model->load($_GET); - $relAttributes = $model->attributes; + $model->load($this->request->get()); + $relAttributes = $model->attributes; if($relAttributes){ return $this->redirect(Url::previous()); - } - + } + // TODO: improve detection $isPivot = strstr('',','); if ($isPivot == true) { @@ -248,23 +248,23 @@ public function actionDelete() * Update model record by editable. * * @return mixed - */ + */ public function actionEditable(){ - + // Check if there is an Editable ajax request if (!isset($_POST['hasEditable'])) { return false; } - + $post = []; foreach($_POST as $name => $value){ //if(in_array($name,$this->editAbleFileds)){ $post[$name] = $value; //} } - + // use Yii's response format to encode output as JSON - \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; if(!$post){ return ['output'=>'', 'message'=> generateString('Can not update this field') ?>]; } @@ -288,16 +288,16 @@ public function actionEditable(){ $errors = []; foreach($model->errors as $field => $messages){ foreach($messages as $message){ - $errors[] = $model->getAttributeLabel($field) + $errors[] = $model->getAttributeLabel($field) . ': ' . $message; } } return ['output'=>'', 'message'=>implode('
',$errors)]; - + } - - } + + } /** * Finds the model based on its primary key value. diff --git a/src/generators/crud/editable/migration_access.php b/src/generators/crud/editable/migration_access.php index 3e708e85..0a841eea 100644 --- a/src/generators/crud/editable/migration_access.php +++ b/src/generators/crud/editable/migration_access.php @@ -13,26 +13,26 @@ class migrationClass?> extends Migration /** * @var array controller all actions */ - public $permisions = var_export54($accessDefinitions['permisions'],' ')?>; + public $permissions = var_export54($accessDefinitions['permissions'],' ')?>; /** - * @var array roles and maping to actions/permisions + * @var array roles and maping to actions/permissions */ public $roles = var_export54($accessDefinitions['roles'],' ')?>; public function up() { - $permisions = []; + $permissions = []; $auth = \Yii::$app->authManager; /** - * create permisions for each controller action + * create permissions for each controller action */ - foreach ($this->permisions as $action => $permission) { - $permisions[$action] = $auth->createPermission($permission['name']); - $permisions[$action]->description = $permission['description']; - $auth->add($permisions[$action]); + foreach ($this->permissions as $action => $permission) { + $permissions[$action] = $auth->createPermission($permission['name']); + $permissions[$action]->description = $permission['description']; + $auth->add($permissions[$action]); } /** @@ -46,7 +46,7 @@ public function up() * to role assign permissions */ foreach ($actions as $action) { - $auth->addChild($role, $permisions[$action]); + $auth->addChild($role, $permissions[$action]); } } } @@ -59,7 +59,7 @@ public function down() { $auth->remove($role); } - foreach ($this->permisions as $permission) { + foreach ($this->permissions as $permission) { $authItem = $auth->createPermission($permission['name']); $auth->remove($authItem); } diff --git a/src/generators/crud/editable/views/_form.php b/src/generators/crud/editable/views/_form.php index 47ed8ea0..27a8c01e 100644 --- a/src/generators/crud/editable/views/_form.php +++ b/src/generators/crud/editable/views/_form.php @@ -27,7 +27,7 @@ * @var yii\web\View $this * @var modelClass, '\\') ?> $model * @var yii\widgets\ActiveForm $form -* @var string $relAttributes relation fields names for disabling +* @var string $relAttributes relation fields names for disabling */ ?> @@ -79,11 +79,11 @@ endBlock(); ?>'; ?> Yii::t('$generator->messageCategory', StringHelper::basename('{$model::className()}')), + 'label' => Yii::t('$generator->messageCategory', StringHelper::basename('{$model::class}')), 'content' => \$this->blocks['main'], 'active' => true, ], diff --git a/src/generators/crud/editable/views/create.php b/src/generators/crud/editable/views/create.php index 7383a659..782fae2b 100644 --- a/src/generators/crud/editable/views/create.php +++ b/src/generators/crud/editable/views/create.php @@ -3,7 +3,7 @@ use yii\helpers\Inflector; use yii\helpers\StringHelper; -/* +/** * @var yii\web\View $this * @var yii\gii\generators\crud\Generator $generator */ @@ -11,7 +11,7 @@ /** @var \yii\db\ActiveRecord $model */ $model = new $generator->modelClass(); $model->setScenario('crud'); -$modelName = StringHelper::basename($model::className()); +$modelName = StringHelper::basename($model::class); echo "title = generateString('Create') ?>; -$this->params['breadcrumbs'][] = ['label' => Yii::t('messageCategory ?>', ''), 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => Yii::t('messageCategory ?>', ''), 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; ?>
diff --git a/src/generators/crud/editable/views/index.php b/src/generators/crud/editable/views/index.php index 382b21b4..34264164 100644 --- a/src/generators/crud/editable/views/index.php +++ b/src/generators/crud/editable/views/index.php @@ -15,7 +15,7 @@ $model = new $generator->modelClass(); $model->setScenario('crud'); -$modelName = Inflector::pluralize(StringHelper::basename($model::className())); +$modelName = Inflector::pluralize(StringHelper::basename($model::class)); $safeAttributes = $model->safeAttributes(); if (empty($safeAttributes)) { @@ -56,15 +56,15 @@ */ $actionColumnTemplates = []; -if (\Yii::$app->user->can('')) { +if (\Yii::$app->user->can('')) { $actionColumnTemplates[] = '{view}'; } -if (\Yii::$app->user->can('')) { +if (\Yii::$app->user->can('')) { $actionColumnTemplates[] = '{update}'; } -if (\Yii::$app->user->can('')) { +if (\Yii::$app->user->can('')) { $actionColumnTemplates[] = '{delete}'; }
accessFilter){ +if($generator->accessFilter){ echo " -if(\Yii::$app->user->can('')){ +if(\Yii::$app->user->can('')){ \n" ?> @@ -187,7 +187,7 @@ 'layout' => '{summary}{pager}{items}{pager}', 'dataProvider' => $dataProvider, 'pager' => [ - 'class' => yii\widgets\LinkPager::className(), + 'class' => yii\widgets\LinkPager::class, 'firstPageLabel' => generateString('First') ?>, 'lastPageLabel' => generateString('Last') ?> ], diff --git a/src/generators/crud/editable/views/update.php b/src/generators/crud/editable/views/update.php index 93d8fed6..e4116dfd 100644 --- a/src/generators/crud/editable/views/update.php +++ b/src/generators/crud/editable/views/update.php @@ -3,7 +3,7 @@ use yii\helpers\Inflector; use yii\helpers\StringHelper; -/* +/** * @var yii\web\View $this * @var yii\gii\generators\crud\Generator $generator */ @@ -11,8 +11,8 @@ $urlParams = $generator->generateUrlParams(); $model = new $generator->modelClass(); $model->setScenario('crud'); -$className = $model::className(); -$modelName = StringHelper::basename($model::className()); +$className = $model::class; +$modelName = StringHelper::basename($model::class); echo " diff --git a/src/generators/crud/editable/views/view.php b/src/generators/crud/editable/views/view.php index a21ad79f..1f785fdc 100644 --- a/src/generators/crud/editable/views/view.php +++ b/src/generators/crud/editable/views/view.php @@ -3,7 +3,7 @@ use yii\helpers\Inflector; use yii\helpers\StringHelper; -/* +/** * @var yii\web\View $this * @var schmunk42\giiant\generators\crud\Generator $generator */ @@ -11,9 +11,9 @@ /** @var \yii\db\ActiveRecord $model */ $model = new $generator->modelClass(); $model->setScenario('crud'); -$modelName = StringHelper::basename($model::className()); +$modelName = StringHelper::basename($model::class); -$className = $model::className(); +$className = $model::class; $safeAttributes = $model->safeAttributes(); if (empty($safeAttributes)) { @@ -104,12 +104,12 @@ 'attributes' => [ isPrimaryKey([$attribute])){ continue; - } - + } + $format = $generator->attributeEditable($attribute); if (!$format) { continue; @@ -156,10 +156,10 @@ $pjaxId = "pjax-{$name}"; $gridRelation = $relation; $gridName = $name; - } - - $gridModel = new $gridRelation->modelClass(); - + } + + $gridModel = new $gridRelation->modelClass(); + $showAllRecords = false; if ($relation->via !== null) { @@ -181,7 +181,7 @@ } // HEADER, relation list, add, create buttons - $headerLabel = Inflector::camel2words($name); + $headerLabel = Inflector::camel2words($name); echo "
@@ -218,7 +218,7 @@ // render relation grid if (!empty($output)): echo "'pjax-{$name}', 'enableReplaceState'=> false, 'linkSelector'=>'#pjax-{$name} ul.pagination a, th a', 'clientOptions' => ['pjax:success'=>'function(){alert(\"yo\")}']]) ?>\n"; - echo '
'.PHP_EOL; + echo '
'.PHP_EOL; echo ' \n"; echo '
'.PHP_EOL; echo "\n"; @@ -235,7 +235,7 @@
=$this->blocks['modelClass?>']?>
-
@@ -244,5 +244,5 @@ -
+
diff --git a/src/generators/crud/providers/core/CallbackProvider.php b/src/generators/crud/providers/core/CallbackProvider.php index f69c5766..0899e740 100755 --- a/src/generators/crud/providers/core/CallbackProvider.php +++ b/src/generators/crud/providers/core/CallbackProvider.php @@ -7,6 +7,8 @@ */ namespace schmunk42\giiant\generators\crud\providers\core; +use yii\base\BaseObject; + class CallbackProvider extends \schmunk42\giiant\base\Provider { public $activeFields = []; @@ -66,7 +68,7 @@ public function partialView($name, $model, $generator) private function getModelKey($attribute, $model) { - return $model::className().'.'.$attribute; + return $model::className() . '.' . $attribute; } private function findValue($subject, $array) diff --git a/src/generators/crud/providers/core/OptsProvider.php b/src/generators/crud/providers/core/OptsProvider.php index 3ce3091d..a34d13d7 100644 --- a/src/generators/crud/providers/core/OptsProvider.php +++ b/src/generators/crud/providers/core/OptsProvider.php @@ -42,7 +42,7 @@ public function activeField($attribute) case 'select2': return <<field(\$model, '{$attribute}')->widget(\kartik\select2\Select2::classname(), [ + \$form->field(\$model, '{$attribute}')->widget(\kartik\select2\Select2::class, [ 'name' => 'class_name', 'model' => \$model, 'attribute' => '{$attribute}', diff --git a/src/generators/crud/providers/core/RelationProvider.php b/src/generators/crud/providers/core/RelationProvider.php index 97ac2aff..158b9f05 100644 --- a/src/generators/crud/providers/core/RelationProvider.php +++ b/src/generators/crud/providers/core/RelationProvider.php @@ -5,6 +5,7 @@ * Date: 14.03.14 * Time: 10:21. */ + namespace schmunk42\giiant\generators\crud\providers\core; use schmunk42\giiant\generators\model\Generator as ModelGenerator; @@ -54,18 +55,20 @@ public function activeField($attribute) if (is_string($column)) { return null; } - $relation = $this->generator->getRelationByColumn($this->generator->modelClass, $column, ['belongs_to']); + $relation = $this->generator->getRelationByColumn($this->generator->modelClass, $column, + ['belongs_to', 'has_one']); if ($relation) { switch (true) { case !$relation->multiple: $pk = key($relation->link); $name = $this->generator->getModelNameAttribute($relation->modelClass); - $method = __METHOD__; + $isRequired = $relation->primaryModel->isAttributeRequired($column->name) ? 'false' : 'true'; + $method = __METHOD__; switch ($this->inputWidget) { case 'select2': $code = <<field(\$model, '{$column->name}')->widget(\kartik\select2\Select2::classname(), [ +\$form->field(\$model, '{$column->name}')->widget(\kartik\select2\Select2::class, [ 'name' => 'class_name', 'model' => \$model, 'attribute' => '{$column->name}', @@ -74,6 +77,9 @@ public function activeField($attribute) 'placeholder' => {$this->generator->generateString('Type to autocomplete')}, 'multiple' => false, 'disabled' => (isset(\$relAttributes) && isset(\$relAttributes['{$column->name}'])), + ], + 'pluginOptions' => [ + 'allowClear' => {$isRequired} ] ]); EOS; @@ -128,7 +134,8 @@ public function attributeFormat($attribute) //return null; #TODO: double check with primary keys not named `id` of non-pivot tables } - $relation = $this->generator->getRelationByColumn($this->generator->modelClass, $column, ['belongs_to']); + $relation = $this->generator->getRelationByColumn($this->generator->modelClass, $column, + ['belongs_to', 'has_one']); if ($relation) { if ($relation->multiple) { return; @@ -141,12 +148,14 @@ public function attributeFormat($attribute) $routeIndex = $this->generator->createRelationRoute($relation, 'index'); $modelClass = $this->generator->modelClass; - $relationProperty = lcfirst((new ModelGenerator())->generateRelationName( - [$relation], - $modelClass::getTableSchema(), - $column->name, - $relation->multiple - )); + $relationProperty = lcfirst((new ModelGenerator([ + 'disablePluralization' => $this->generator->disablePluralization + ]))->generateRelationName( + [$relation], + $modelClass::getTableSchema(), + $column->name, + $relation->multiple + )); $relationModel = new $relation->modelClass(); $relationModelName = StringHelper::basename($modelClass); $pks = $relationModel->primaryKey(); @@ -204,7 +213,7 @@ public function columnFormat($attribute, $model) //return null; } - $relation = $this->generator->getRelationByColumn($model, $column, ['belongs_to']); + $relation = $this->generator->getRelationByColumn($model, $column, ['belongs_to', 'has_one']); if ($relation) { if ($relation->multiple) { return; @@ -214,11 +223,11 @@ public function columnFormat($attribute, $model) $method = __METHOD__; $modelClass = $this->generator->modelClass; $relationProperty = lcfirst((new ModelGenerator())->generateRelationName( - [$relation], - $modelClass::getTableSchema(), - $column->name, - $relation->multiple - )); + [$relation], + $modelClass::getTableSchema(), + $column->name, + $relation->multiple + )); $relationModel = new $relation->modelClass(); $pks = $relationModel->primaryKey(); $paramArrayItems = ''; @@ -233,13 +242,13 @@ public function columnFormat($attribute, $model) $name = $this->generator->getModelNameAttribute($relation->modelClass); $pk = key($relation->link); - $filter = "\n'filter' => \yii\helpers\ArrayHelper::map({$relation->modelClass}::find()->select(['{$pk}', '{$name}'])->asArray()->all(), '{$pk}', '{$name}'),"; + $filter = "\n'filter' => \yii\helpers\ArrayHelper::map({$relation->modelClass}::find()->all(), '{$pk}', '{$name}'),"; } $code = << yii\\grid\\DataColumn::className(), + 'class' => yii\\grid\\DataColumn::class, 'attribute' => '{$column->name}', 'value' => function (\$model) { if (\$rel = \$model->{$relationProperty}) { @@ -308,14 +317,14 @@ public function relationGrid($name, $relation, $showAllRecords = false) } $reflection = new \ReflectionClass($relation->modelClass); - $controller = $this->generator->pathPrefix.Inflector::camel2id($reflection->getShortName(), '-', true); + $controller = $this->generator->pathPrefix . Inflector::camel2id($reflection->getShortName(), '-', true); $relKey = key($relation->link); $actionColumn = << '{$this->generator->actionButtonClass}', 'template' => '$template', 'contentOptions' => ['nowrap'=>'nowrap'], - 'urlCreator' => function (\$action, \$model, \$key, \$index) { + 'urlCreator' => function (\$action, \$model, \$key) { // using the column name as key, not mapping to 'id' like the standard generator \$params = is_array(\$key) ? \$key : [\$model->primaryKey()[0] => (string) \$key]; \$params[0] = '$controller' . '/' . \$action; @@ -330,19 +339,26 @@ public function relationGrid($name, $relation, $showAllRecords = false) EOS; // add action column - if ($this->generator->actionButtonColumnPosition != 'right') { + if ($this->generator->actionButtonColumnPosition !== 'right') { $columns .= $actionColumn . ",\n"; } // prepare grid column formatters - $model->setScenario('crud'); + if (array_key_exists('crud-relation-list', $model->scenarios())) { + $model->setScenario('crud-relation-list'); + } else if (array_key_exists('crud-list', $model->scenarios())) { + $model->setScenario('crud-list'); + } else { + $model->setScenario('crud'); + } $safeAttributes = $model->safeAttributes(); if (empty($safeAttributes)) { $safeAttributes = $model->getTableSchema()->columnNames; } + foreach ($safeAttributes as $attr) { - // max seven columns + // max defined amount of columns if ($counter > $this->generator->gridRelationMaxColumns) { continue; } @@ -351,19 +367,19 @@ public function relationGrid($name, $relation, $showAllRecords = false) continue; } // don't show current model - if (key($relation->link) == $attr) { + if (key($relation->link) === $attr && !in_array($attr, $safeAttributes, true)) { continue; } $code = $this->generator->columnFormat($attr, $model); - if ($code == false) { + if ($code === false) { continue; } - $columns .= $code.",\n"; + $columns .= $code . ",\n"; ++$counter; } - if ($this->generator->actionButtonColumnPosition == 'right') { + if ($this->generator->actionButtonColumnPosition === 'right') { $columns .= $actionColumn . ",\n"; } @@ -385,7 +401,7 @@ public function relationGrid($name, $relation, $showAllRecords = false) ] ]), 'pager' => [ - 'class' => yii\widgets\LinkPager::className(), + 'class' => yii\widgets\LinkPager::class, 'firstPageLabel' => {$firstPageLabel}, 'lastPageLabel' => {$lastPageLabel} ], diff --git a/src/generators/crud/providers/extensions/DateProvider.php b/src/generators/crud/providers/extensions/DateProvider.php index 51651eb2..583ac54b 100644 --- a/src/generators/crud/providers/extensions/DateProvider.php +++ b/src/generators/crud/providers/extensions/DateProvider.php @@ -17,7 +17,7 @@ public function activeField($attribute) $this->generator->requires[] = 'zhuravljov/yii2-datetime-widgets'; return <<field(\$model, '{$column->name}')->widget(\zhuravljov\widgets\DatePicker::className(), [ +\$form->field(\$model, '{$column->name}')->widget(\zhuravljov\widgets\DatePicker::class, [ 'options' => ['class' => 'form-control'], 'clientOptions' => [ 'autoclose' => true, diff --git a/src/generators/crud/providers/extensions/DateTimeProvider.php b/src/generators/crud/providers/extensions/DateTimeProvider.php index c3a82841..c82c773f 100644 --- a/src/generators/crud/providers/extensions/DateTimeProvider.php +++ b/src/generators/crud/providers/extensions/DateTimeProvider.php @@ -11,7 +11,7 @@ public function activeField($attribute) $this->generator->requires[] = 'zhuravljov/yii2-datetime-widgets'; return <<field(\$model, '{$attribute}')->widget(\zhuravljov\widgets\DateTimePicker::className(), [ +\$form->field(\$model, '{$attribute}')->widget(\zhuravljov\widgets\DateTimePicker::class, [ 'options' => ['class' => 'form-control'], 'clientOptions' => [ 'autoclose' => true, diff --git a/src/generators/crud/providers/extensions/EditorProvider.php b/src/generators/crud/providers/extensions/EditorProvider.php index fec59a03..1875ca39 100644 --- a/src/generators/crud/providers/extensions/EditorProvider.php +++ b/src/generators/crud/providers/extensions/EditorProvider.php @@ -29,29 +29,29 @@ public function activeField($attribute) case 'redactor': $this->generator->requires[] = 'yiidoc/yii2-redactor'; - return "\$form->field(\$model, '{$attribute}')->widget(\\yii\\redactor\\widgets\\Redactor::className())"; + return "\$form->field(\$model, '{$attribute}')->widget(\\yii\\redactor\\widgets\\Redactor::class)"; break; case 'aceHTML': $this->generator->requires[] = 'trntv/aceeditor'; - return "\$form->field(\$model, '{$attribute}')->widget(\\trntv\\aceeditor\\AceEditor::className(), ['mode' => 'html', 'theme' => 'twilight'])"; + return "\$form->field(\$model, '{$attribute}')->widget(\\trntv\\aceeditor\\AceEditor::class, ['mode' => 'html', 'theme' => 'twilight'])"; break; case 'aceLESS': $this->generator->requires[] = 'trntv/aceeditor'; - return "\$form->field(\$model, '{$attribute}')->widget(\\trntv\\aceeditor\\AceEditor::className(), ['mode' => 'less', 'theme' => 'twilight'])"; + return "\$form->field(\$model, '{$attribute}')->widget(\\trntv\\aceeditor\\AceEditor::class, ['mode' => 'less', 'theme' => 'twilight'])"; break; case 'aceJS': $this->generator->requires[] = 'trntv/aceeditor'; - return "\$form->field(\$model, '{$attribute}')->widget(\\trntv\\aceeditor\\AceEditor::className(), ['mode' => 'javascript', 'theme' => 'twilight'])"; + return "\$form->field(\$model, '{$attribute}')->widget(\\trntv\\aceeditor\\AceEditor::class, ['mode' => 'javascript', 'theme' => 'twilight'])"; break; default: $this->generator->requires[] = '2amigos/yii2-ckeditor-widget'; return <<field(\$model, '{$attribute}')->widget( - \dosamigos\ckeditor\CKEditor::className(), + \dosamigos\ckeditor\CKEditor::class, [ 'options' => ['rows' => 6], 'preset' => 'basic' diff --git a/src/generators/extension/default/Bootstrap.php b/src/generators/extension/default/Bootstrap.php index 7054e2ae..7cbeb802 100644 --- a/src/generators/extension/default/Bootstrap.php +++ b/src/generators/extension/default/Bootstrap.php @@ -11,19 +11,19 @@ class Bootstrap implements BootstrapInterface { /** @inheritdoc */ public function bootstrap($app) { -enableI18N){ -?> +?> if (!isset($app->get('i18n')->translations['messageCategory ?>*'])) { $app->get('i18n')->translations['messageCategory ?>*'] = [ - 'class' => PhpMessageSource::className(), + 'class' => PhpMessageSource::class, 'basePath' => __DIR__ . '/messages', 'sourceLanguage' => 'en-US' ]; } +?> } } diff --git a/src/generators/model/Generator.php b/src/generators/model/Generator.php index 24102ee5..c7c49332 100644 --- a/src/generators/model/Generator.php +++ b/src/generators/model/Generator.php @@ -5,6 +5,7 @@ * @copyright Copyright (c) 2014 herzog kommunikation GmbH * @license http://www.phundament.com/license/ */ + namespace schmunk42\giiant\generators\model; use schmunk42\giiant\helpers\SaveForm; @@ -93,11 +94,21 @@ class Generator extends \yii\gii\generators\model\Generator */ public $baseClassPrefix = ''; + /** + * @var string prefix to prepend to the many many relation methods + */ + public $manyManyRelationSuffix = ''; + /** * @var string suffix to append to the base model, setting "Base" will result in a model named "PostBase" */ public $baseClassSuffix = ''; + /** + * @var bool whether to enable or disable the pluralization of the models name + */ + public $disablePluralization = false; + /** * @var array key-value pairs for mapping a table-name to class-name, eg. 'prefix_FOObar' => 'FooBar' */ @@ -127,6 +138,24 @@ class Generator extends \yii\gii\generators\model\Generator protected static $_relationsCache = null; + /** + * the names given here are used as suffixes to the base_translation table name, eg. + * + * $languageTableName = '{table}_translation'; + * $translationTableAdditions = ['meta']; + * + * will process {table}_translation AND {table}_translation_meta + * + * to be able to set the 'fallbackLanguage' flag fot the behaviour of this translation, items can be arrays like: + * + * $translationTableAdditions = ['name' => 'meta', 'fallbackLanguage' => false] + * + * if fallbackLanguage is not specified, 'true' is used as default + * + * @var array af additional translation tables + */ + public $translationTableAdditions = ['name' => 'meta', 'fallbackLanguage' => false]; + /** * {@inheritdoc} */ @@ -151,15 +180,30 @@ public function rules() return array_merge( parent::rules(), [ - [[ - 'generateModelClass', - 'useTranslatableBehavior', - 'generateHintsFromComments', - 'useBlameableBehavior', - 'useTimestampBehavior', - 'singularEntities', - ], 'boolean'], - [['languageTableName', 'languageCodeColumn', 'createdByColumn', 'updatedByColumn', 'createdAtColumn', 'updatedAtColumn', 'savedForm', 'timestampBehaviorClass'], 'string'], + [ + [ + 'generateModelClass', + 'useTranslatableBehavior', + 'generateHintsFromComments', + 'useBlameableBehavior', + 'useTimestampBehavior', + 'singularEntities', + ], + 'boolean' + ], + [ + [ + 'languageTableName', + 'languageCodeColumn', + 'createdByColumn', + 'updatedByColumn', + 'createdAtColumn', + 'updatedAtColumn', + 'savedForm', + 'timestampBehaviorClass' + ], + 'string' + ], [['tablePrefix'], 'safe'], ] ); @@ -181,7 +225,7 @@ public function formAttributes() 'db', 'generateRelations', 'generateJunctionRelationMode', - //'generateRelationsFromCurrentSchema', + 'generateRelationsFromCurrentSchema', 'generateLabelsFromComments', 'generateHintsFromComments', 'generateModelClass', @@ -202,7 +246,7 @@ public function formAttributes() 'createdAtColumn', 'updatedAtColumn', 'timestampBehaviorClass', - ]; + ]; } /** @@ -272,9 +316,10 @@ public function generate() $db = $this->getDbConnection(); + $generateTranslationTrait = false; + foreach ($this->getTableNames() as $tableName) { list($relations, $translations) = array_values($this->extractTranslations($tableName, $relations)); -//var_dump($relations,$tableName);exit; $className = $this->modelClass === '' || php_sapi_name() === 'cli' ? $this->generateClassName($tableName) : $this->modelClass; @@ -290,13 +335,16 @@ public function generate() 'labels' => $this->generateLabels($tableSchema), 'hints' => $this->generateHints($tableSchema), 'rules' => $this->generateRules($tableSchema), - 'relations' => isset($relations[$tableName]) ? $relations[$tableName] : [], + 'relations' => $relations[$tableName] ?? [], 'ns' => $this->ns, 'enum' => $this->getEnum($tableSchema->columns), + 'traits' => (array)$this->baseTraits ]; if (!empty($translations)) { $params['translation'] = $translations; + $params['traits'][] = '\\' . $this->ns . '\traits\TranslationAttributeRules'; + $generateTranslationTrait = true; } $params['blameable'] = $this->generateBlameable($tableSchema); @@ -309,7 +357,7 @@ public function generate() $this->render('model.php', $params) ); - $modelClassFile = Yii::getAlias('@'.str_replace('\\', '/', $this->ns)).'/'.$className.'.php'; + $modelClassFile = Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $className . '.php'; if ($this->generateModelClass || !is_file($modelClassFile)) { $files[] = new CodeFile( $modelClassFile, @@ -319,8 +367,8 @@ public function generate() if ($queryClassName) { $queryClassFile = Yii::getAlias( - '@'.str_replace('\\', '/', $this->queryNs) - ).'/'.$queryClassName.'.php'; + '@' . str_replace('\\', '/', $this->queryNs) + ) . '/' . $queryClassName . '.php'; if ($this->generateModelClass || !is_file($queryClassFile)) { $params = [ 'className' => $queryClassName, @@ -337,17 +385,28 @@ public function generate() * create gii/[name]GiiantModel.json with actual form data */ $suffix = str_replace(' ', '', $this->getName()); - $formDataDir = Yii::getAlias('@'.str_replace('\\', '/', $this->ns)); + $formDataDir = Yii::getAlias('@' . str_replace('\\', '/', $this->ns)); $formDataFile = StringHelper::dirname($formDataDir) - .'/'.$this->giiInfoPath.'/' - .'/'.$tableName.$suffix.'.json'; + . '/' . $this->giiInfoPath . '/' + . '/' . $tableName . $suffix . '.json'; $generatorForm = (clone $this); $generatorForm->tableName = $tableName; - $generatorForm->modelClass = $className; - $formData = json_encode(SaveForm::getFormAttributesValues($generatorForm, $this->formAttributes()), JSON_PRETTY_PRINT); + $generatorForm->modelClass = $className; + $formData = json_encode(SaveForm::getFormAttributesValues($generatorForm, $this->formAttributes()), + JSON_PRETTY_PRINT); $files[] = new CodeFile($formDataFile, $formData); } + if ($generateTranslationTrait) { + $files[] = new CodeFile( + Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/traits/TranslationAttributeRules.php', + $this->render('translation-trait.php', [ + 'ns' => $this->ns . '\traits' + ]) + ); + } + + return $files; } @@ -389,7 +448,7 @@ public function generateClassName($tableName, $useSchemaName = null) if (($pos = strrpos($pattern, '.')) !== false) { $pattern = substr($pattern, $pos + 1); } - $patterns[] = '/^'.str_replace('*', '(\w+)', $pattern).'$/'; + $patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/'; } $className = $tableName; @@ -439,7 +498,15 @@ public function generateHints($table) */ public function generateRelationName($relations, $table, $key, $multiple) { - return parent::generateRelationName($relations, $table, $key, $multiple); + $suffix = ''; + if ($this->disablePluralization) { + if ($multiple) { + $suffix = $this->manyManyRelationSuffix; + } + $multiple = false; + } + $relationName = parent::generateRelationName($relations, $table, $key, $multiple); + return $relationName . $suffix; } protected function generateRelations() @@ -485,8 +552,8 @@ public function getEnum($columns) } $column_camel_name = str_replace(' ', '', ucwords(implode(' ', explode('_', $column->name)))); - $enum[$column->name]['func_opts_name'] = 'opts'.$column_camel_name; - $enum[$column->name]['func_get_label_name'] = 'get'.$column_camel_name.'ValueLabel'; + $enum[$column->name]['func_opts_name'] = 'opts' . $column_camel_name; + $enum[$column->name]['func_get_label_name'] = 'get' . $column_camel_name . 'ValueLabel'; $enum[$column->name]['values'] = []; $enum_values = explode(',', substr($column->dbType, 4, strlen($column->dbType) - 1)); @@ -494,7 +561,7 @@ public function getEnum($columns) foreach ($enum_values as $value) { $value = trim($value, "()'"); - $const_name = strtoupper($column->name.'_'.$value); + $const_name = strtoupper($column->name . '_' . $value); $const_name = preg_replace('/\s+/', '_', $const_name); $const_name = str_replace(['-', '_', ' '], '_', $const_name); $const_name = preg_replace('/[^A-Z0-9_]/', '', $const_name); @@ -552,21 +619,36 @@ public function generateRules($table) foreach ($enum as $field_name => $field_details) { $ea = array(); foreach ($field_details['values'] as $field_enum_values) { - $ea[] = 'self::'.$field_enum_values['const_name']; + $ea[] = 'self::' . $field_enum_values['const_name']; } - $rules[] = "['".$field_name."', 'in', 'range' => [\n ".implode( + $rules[] = "['" . $field_name . "', 'in', 'range' => [\n " . implode( ",\n ", $ea - ).",\n ]\n ]"; + ) . ",\n ]\n ]"; } // inject namespace for targetClass $parentRules = parent::generateRules($table); $ns = "\\{$this->ns}\\"; $match = "'targetClass' => "; - $replace = $match.$ns; + $replace = $match . $ns; + + + $replaceMap = [ + [ + 'search' => "'targetClass' => ", + 'replace' => "'targetClass' => " . $ns, + ], + [ + 'search' => "'unique', ", + 'replace' => "'unique', 'targetClass' => " . $ns . $this->modelClass . '::class, ', + ] + ]; foreach ($parentRules as $k => $parentRule) { - $parentRules[$k] = str_replace($match, $replace, $parentRule); + foreach ($replaceMap as $replaceItem) { + $parentRules[$k] = str_replace($replaceItem['search'], $replaceItem['replace'], $parentRule); + break; + } } $rules = array_merge($parentRules, $rules); @@ -593,10 +675,10 @@ protected function getDbConnection() public function validateDb() { if (Yii::$container->has($this->db)) { - return true; - } else { - return parent::validateDb(); + return; } + + parent::validateDb(); } /** @@ -608,11 +690,65 @@ public function getTableNames() } /** - * @param $relations all database's relations + * @return array associative array containing the extracted relations and the modified translations (from parent) + translations_meta fields if exists + */ + protected function extractTranslations($tableName, $relations) { + + $translations = [ + 'relations' => $relations, + 'translations' => [], + ]; + + # check if we have base translations + $baseTranslations = $this->extractBaseTranslations($tableName, $relations); + // we do not want timestamp columns as translatable fields + $unsetFields = [$this->createdAtColumn, $this->updatedAtColumn, $this->createdByColumn, $this->updatedByColumn]; + if (!empty($baseTranslations['translations']['fields'])) { + $translations = $baseTranslations; + $translations['translations']['fields'] = array_diff($baseTranslations['translations']['fields'], $unsetFields); + } + + $baseLanguageTableName = $this->languageTableName; + foreach ($this->translationTableAdditions as $addition) { + + if (is_array($addition)) { + $additionName = $addition['name']; + $additionFallbackLanguage = $addition['fallbackLanguage'] ?? true; + } else { + $additionName = $addition; + $additionFallbackLanguage = true; + } + + # in the following runs we must use possibly modified relations from previous extractTranslations() call + $prevRelations = $translations['relations']; + # to be able to reuse extractTranslations() set $this->languageTableName for one method call + $this->languageTableName .= '_' . $additionName; + # here we must use possibly modified relations from previous extractTranslations() call + $additionTranslations = $this->extractBaseTranslations($tableName, $prevRelations); + + # if we get meta-translations fields, overwrite relations, + # otherwise we get the relation as TranslationMetas and translationMetas + if (!empty($additionTranslations['translations']['fields'])) { + $translations['relations'] = $additionTranslations['relations']; + $translations['translations']['additions'][$additionName]['fields'] = array_diff($additionTranslations['translations']['fields'], $unsetFields); + $translations['translations']['additions'][$additionName]['code'] = $additionTranslations['translations']['code']; + # set flag if this addition should use the fallback language feature + $translations['translations']['additions'][$additionName]['fallbackLanguage'] = $additionFallbackLanguage; + } + # reset languageTableName to default value (without prefix) + $this->languageTableName = $baseLanguageTableName; + } + + return $translations; + + } + + /** + * @param array $relations All database's relations * * @return array associative array containing the extracted relations and the modified translations */ - protected function extractTranslations($tableName, $relations) + protected function extractBaseTranslations($tableName, $relations) { $langTableName = str_replace('{{table}}', $tableName, $this->languageTableName); @@ -700,10 +836,21 @@ protected function generateTimestamp($table) $createdAt = $table->getColumn($this->createdAtColumn) !== null ? $this->createdAtColumn : false; $updatedAt = $table->getColumn($this->updatedAtColumn) !== null ? $this->updatedAtColumn : false; + #var_dump($table->getColumn($this->createdAtColumn)); exit; if ($this->useTimestampBehavior && ($createdAt || $updatedAt)) { + // check column type, if datetime set NOW() as Value + if ($table->getColumn($this->createdAtColumn)->type === 'datetime') { + return [ + 'value' => '(new \DateTime())->format(\'Y-m-d H:i:s\')', + 'createdAtAttribute' => $createdAt, + 'updatedAtAttribute' => $updatedAt, + 'timestampBehaviorClass' => $this->timestampBehaviorClass, + ]; + + } return [ - 'createdAtAttribute' => $createdAt, - 'updatedAtAttribute' => $updatedAt, + 'createdAtAttribute' => $createdAt, + 'updatedAtAttribute' => $updatedAt, 'timestampBehaviorClass' => $this->timestampBehaviorClass, ]; } diff --git a/src/generators/model/default/model-extended.php b/src/generators/model/default/model-extended.php index 4a6f5100..a2890547 100644 --- a/src/generators/model/default/model-extended.php +++ b/src/generators/model/default/model-extended.php @@ -17,9 +17,7 @@ namespace ns ?>; -use Yii; use \ns ?>\base\ as Base; -use yii\helpers\ArrayHelper; /** * This is the model class for table "". @@ -27,23 +25,4 @@ class extends Base { - public function behaviors() - { - return ArrayHelper::merge( - parent::behaviors(), - [ - # custom behaviors - ] - ); - } - - public function rules() - { - return ArrayHelper::merge( - parent::rules(), - [ - # custom validation rules - ] - ); - } } diff --git a/src/generators/model/default/model.php b/src/generators/model/default/model.php index f6885c2b..955f9020 100644 --- a/src/generators/model/default/model.php +++ b/src/generators/model/default/model.php @@ -11,12 +11,19 @@ * @var schmunk42\giiant\generators\model\Generator $generator * @var string $tableName full table name * @var string $className class name + * @var string $ns class namespace + * @var string $queryClassName queryclass name * @var yii\db\TableSchema $tableSchema * @var string[] $labels list of attribute labels (name => label) * @var string[] $rules list of validation rules * @var array $relations list of relations (name => relation declaration) + * @var array $translation + * @var array $traits */ +$activeRecordClass = '\\' . ltrim($generator->baseClass, '\\'); +$translationExists = false; + echo " // This class was automatically generated by a giiant build task @@ -35,6 +42,9 @@ use ; + +use ns .'\\base' === $generator->queryNs ? $queryClassName : '\\' . $generator->queryNs . '\\' . $queryClassName) ?>; + /** * This is the base-model class for table "". @@ -48,19 +58,15 @@ * @property \\ - * @property string $aliasModel */ -abstract class extends baseClass, '\\') . "\n" ?> +abstract class extends { - baseTraits; - if ($traits) { - echo "use {$traits};"; + if (!empty($traits)) { + echo "\tuse " . implode(', ', $traits) . ';' . PHP_EOL; } ?> - @@ -86,6 +92,7 @@ public static function tableName() /** * @return \yii\db\Connection the database connection used by this AR class. + * @throws \yii\base\InvalidConfigException */ public static function getDb() { @@ -99,43 +106,78 @@ public static function getDb() */ public function behaviors() { - return [ - - [ - 'class' => BlameableBehavior::className(), - - 'createdByAttribute' => , - - - 'updatedByAttribute' => , - - ], - - - [ - 'class' => TimestampBehavior::className(), - - 'createdAtAttribute' => , - - - 'updatedAtAttribute' => , - - ], - - - 'translatable' => [ - 'class' => TranslateableBehavior::className(), - // in case you renamed your relation, you can setup its name - // 'relation' => 'translations', -languageCodeColumn !== 'language'): ?> + $behaviors = parent::behaviors(); + + $behaviors['blameable'] = [ + 'class' => BlameableBehavior::class, + + 'createdByAttribute' => , + + + 'updatedByAttribute' => , + +]; + + +$behaviors['timestamp'] = [ + 'class' => TimestampBehavior::class, + + 'value' => , + + + 'createdAtAttribute' => , + + + 'updatedAtAttribute' => , + +]; + + + + +$behaviors['translation'] = [ + 'class' => TranslateableBehavior::class, + // 'relation' => 'translations', + languageCodeColumn !== 'language'): ?> 'languageField' => 'languageCodeColumn ?>', - - 'translationAttributes' => [ - - ], + + 'skipSavingDuplicateTranslation' => true, + 'translationAttributes' => [ + ], - + 'deleteEvent' => ::EVENT_BEFORE_DELETE, + 'restrictDeletion' => TranslateableBehavior::DELETE_LAST ]; + + + + $values): ?> + + $behaviors['translation_'] = [ + 'class' => TranslateableBehavior::class, + 'relation' => 'translations', + languageCodeColumn !== 'language'): ?> + 'languageField' => 'languageCodeColumn ?>', + + + // This is not a boolean parameter it only sets the fallbackLanguage to an invalid value! + 'fallbackLanguage' => false, + 'skipSavingDuplicateTranslation' => false, + + 'skipSavingDuplicateTranslation' => true, + + 'translationAttributes' => [ + + ], + 'deleteEvent' => ::EVENT_BEFORE_DELETE + ]; + + + + + + + return $behaviors; } @@ -144,7 +186,11 @@ public function behaviors() */ public function rules() { - return ArrayHelper::merge(parent::rules(), []); + $parentRules = parent::rules(); + + $parentRules += $this->importTranslationAttributeRules(); + + return ArrayHelper::merge($parentRules, []); } /** @@ -152,11 +198,11 @@ public function rules() */ public function attributeLabels() { - return [ + return ArrayHelper::merge(parent::attributeLabels(), [ $label): ?> " . $generator->generateString($label) . ",\n" ?> - ]; + ]); } @@ -165,14 +211,14 @@ public function attributeLabels() */ public function attributeHints() { - return array_merge(parent::attributeHints(), [ + return ArrayHelper::merge(parent::attributeHints(), [ $hint): ?> " . $generator->generateString($hint) . ",\n" ?> ]); } - $relation): ?> + $relation):?> /** * @return \yii\db\ActiveQuery @@ -191,25 +237,34 @@ public function getTranslations() { } - + + $values): ?> + + /** + * @return \yii\db\ActiveQuery + */ + public function getTranslations() + { + + } + + + + + - ns .'\\base' === $generator->queryNs) ? $queryClassName : '\\' . $generator->queryNs . '\\' . $queryClassName; - echo "\n"; - ?> /** * @inheritdoc - * @return the active query used by this AR class. + * @return the active query used by this AR class. */ public static function find() { - return new (get_called_class()); + return new (static::class); } - $column_data){ + foreach($enum as $column_name => $column_data): ?> /** @@ -239,10 +294,5 @@ public static function () ?> ]; } - - + } diff --git a/src/generators/model/default/query.php b/src/generators/model/default/query.php index e6f4b812..1722dd4b 100644 --- a/src/generators/model/default/query.php +++ b/src/generators/model/default/query.php @@ -8,9 +8,10 @@ /* @var $className string class name */ /* @var $modelClassName string related model class name */ -$modelFullClassName = $modelClassName; if ($generator->ns !== $generator->queryNs) { - $modelFullClassName = '\\' . $generator->ns . '\\' . $modelFullClassName; + $modelFullClassName = '\\' . $generator->ns . '\\' . $modelClassName; +} else { + $modelFullClassName = $modelClassName; } echo "queryNs ?>; +use ; + /** - * This is the ActiveQuery class for [[]]. + * This is the ActiveQuery class for [[]]. * * @see + * @method [] all($db = null) + * @method one($db = null) */ class extends queryBaseClass, '\\') . "\n" ?> { - /*public function active() - { - $this->andWhere('[[status]]=1'); - return $this; - }*/ - - /** - * @inheritdoc - * @return []|array - */ - public function all($db = null) - { - return parent::all($db); - } - /** - * @inheritdoc - * @return |array|null - */ - public function one($db = null) - { - return parent::one($db); - } } diff --git a/src/generators/model/default/translation-trait.php b/src/generators/model/default/translation-trait.php new file mode 100644 index 00000000..12e7168e --- /dev/null +++ b/src/generators/model/default/translation-trait.php @@ -0,0 +1,41 @@ + + +namespace ; + +use dosamigos\translateable\TranslateableBehavior; + +trait TranslationAttributeRules +{ + /** + * Import rules from translation model for translation attributes + * + * @return array + */ + public function importTranslationAttributeRules(): array + { + $rules = []; + foreach ($this->getBehaviors() as $behavior) { + if ($behavior instanceof TranslateableBehavior) { + $translationModelClass = $this->getRelation($behavior->relation)->modelClass; + $importRules = (new $translationModelClass)->rules(); + foreach ($importRules as $rule) { + foreach ((array)$rule[0] as $rule_key => $attribute) { + if (!in_array($attribute, $behavior->translationAttributes, true)) { + unset($rule[0][$rule_key]); + } + } + if (!empty($rule[0])) { + $rules[] = $rule; + } + } + } + } + return $rules; + } +}