diff --git a/extensions/gii/Module.php b/extensions/gii/Module.php index 30302b5ef7..0b0f6e4d6e 100644 --- a/extensions/gii/Module.php +++ b/extensions/gii/Module.php @@ -141,6 +141,7 @@ class Module extends \yii\base\Module 'controller' => ['class' => 'yii\gii\generators\controller\Generator'], 'form' => ['class' => 'yii\gii\generators\form\Generator'], 'module' => ['class' => 'yii\gii\generators\module\Generator'], + 'extension' => ['class' => 'yii\gii\generators\extension\Generator'], ]; } } diff --git a/extensions/gii/generators/extension/Generator.php b/extensions/gii/generators/extension/Generator.php new file mode 100644 index 0000000000..96a60adfa1 --- /dev/null +++ b/extensions/gii/generators/extension/Generator.php @@ -0,0 +1,266 @@ + + * @since 2.0 + */ +class Generator extends \yii\gii\Generator +{ + public $vendorName; + public $packageName = "yii2-"; + public $namespace; + public $type = "yii2-extension"; + public $keywords = "yii2,extension"; + public $title; + public $description; + public $outputPath = "@app/runtime/tmp-extensions"; + public $license; + public $authorName; + public $authorEmail; + + /** + * @inheritdoc + */ + public function getName() + { + return 'Extension Generator'; + } + + /** + * @inheritdoc + */ + public function getDescription() + { + return 'This generator helps you to generate the files needed by a Yii extension.'; + } + + /** + * @inheritdoc + */ + public function rules() + { + return array_merge( + parent::rules(), + [ + [['vendorName', 'packageName'], 'filter', 'filter' => 'trim'], + [ + [ + 'vendorName', + 'packageName', + 'namespace', + 'type', + 'license', + 'title', + 'description', + 'authorName', + 'authorEmail', + 'outputPath' + ], + 'required' + ], + [['keywords'], 'safe'], + [['authorEmail'], 'email'], + [ + ['vendorName', 'packageName'], + 'match', + 'pattern' => '/^[a-z0-9\-\.]+$/', + 'message' => 'Only lowercase word characters, dashes and dots are allowed.' + ], + [ + ['namespace'], + 'match', + 'pattern' => '/^[a-zA-Z0-9\\\]+\\\$/', + 'message' => 'Only letters, numbers and backslashes are allowed. PSR-4 namespaces must end with a namespace separator.' + ], + ] + ); + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return [ + 'vendorName' => 'Vendor Name', + 'packageName' => 'Package Name', + 'license' => 'License', + ]; + } + + /** + * @inheritdoc + */ + public function hints() + { + return [ + 'vendorName' => 'This refers to the name of the publisher, your GitHub user name is usually a good choice, eg. myself.', + 'packageName' => 'This is the name of the extension on packagist, eg. yii2-foobar.', + 'namespace' => 'PSR-4, eg. myself\foobar\ This will be added to your autoloading by composer. Do not use yii or yii2 in the namespace.', + 'keywords' => 'Comma separated keywords for this extension.', + 'outputPath' => 'The temporary location of the generated files.', + 'title' => 'A more descriptive name of your application for the README file.', + 'description' => 'A sentence or subline describing the main purpose of the extension.', + ]; + } + + /** + * @inheritdoc + */ + public function stickyAttributes() + { + return ['vendorName', 'outputPath', 'authorName', 'authorEmail']; + } + + /** + * @inheritdoc + */ + public function successMessage() + { + $outputPath = realpath(\Yii::getAlias($this->outputPath)); + $output1 = <<The extension has been generated successfully.

+

To enable it in your application, you need to create a git repository +and require it via composer.

+EOD; + $code1 = <<packageName} + +git init +git add -A +git commit +git remote add origin https://path.to/your/repo +git push -u origin master +EOD; + $output2 = <<The next step is just for initial development, skip it if you directly publish the extension on packagist.org

+

Add the newly created repo to your composer.json.

+EOD; + $code2 = <<Note: You may use the url file://{$outputPath}/{$this->packageName} for testing.

+

Require the package with composer

+EOD; + $code3 = <<vendorName}/{$this->packageName}:dev-master +EOD; + $output4 = <<And use it in your application.

+EOD; + $code4 = <<namespace}AutoloadExample::widget(); +EOD; + $output5 = <<When you have finished development register your extension at packagist.org.

+EOD; + + $return = $output1 . '
' . highlight_string($code1, true) . '
'; + $return .= $output2 . '
' . highlight_string($code2, true) . '
'; + $return .= $output3 . '
' . highlight_string($code3, true) . '
'; + $return .= $output4 . '
' . highlight_string($code4, true) . '
'; + $return .= $output5; + return $return; + } + + /** + * @inheritdoc + */ + public function requiredTemplates() + { + return ['composer.json', 'AutoloadExample.php', 'README.md']; + } + + /** + * @inheritdoc + */ + public function generate() + { + $files = []; + $modulePath = $this->getOutputPath(); + $files[] = new CodeFile( + $modulePath . '/' . $this->packageName . '/composer.json', + $this->render("composer.json") + ); + $files[] = new CodeFile( + $modulePath . '/' . $this->packageName . '/AutoloadExample.php', + $this->render("AutoloadExample.php") + ); + $files[] = new CodeFile( + $modulePath . '/' . $this->packageName . '/README.md', + $this->render("README.md") + ); + return $files; + } + + /** + * @return boolean the directory that contains the module class + */ + public function getOutputPath() + { + return Yii::getAlias($this->outputPath); + } + + /** + * @return a json encoded array with the given keywords + */ + public function getKeywordsArrayJson() + { + return json_encode(explode(',', $this->keywords)); + } + + /** + * @return array options for type drop-down + */ + public function optsType() + { + $licenses = [ + 'yii2-extension', + 'library', + ]; + return array_combine($licenses, $licenses); + } + + /** + * @return array options for license drop-down + */ + public function optsLicense() + { + $licenses = [ + 'Apache-2.0', + 'BSD-2-Clause', + 'BSD-3-Clause', + 'BSD-4-Clause', + 'GPL-2.0', + 'GPL-2.0+', + 'GPL-3.0', + 'GPL-3.0+', + 'LGPL-2.1', + 'LGPL-2.1+', + 'LGPL-3.0', + 'LGPL-3.0+', + 'MIT' + ]; + return array_combine($licenses, $licenses); + } +} diff --git a/extensions/gii/generators/extension/form.php b/extensions/gii/generators/extension/form.php new file mode 100644 index 0000000000..98a250cafc --- /dev/null +++ b/extensions/gii/generators/extension/form.php @@ -0,0 +1,27 @@ + +
+ Please read the + 'new']) ?> + before creating an extension. +
+
+field($generator, 'vendorName'); + echo $form->field($generator, 'packageName'); + echo $form->field($generator, 'namespace'); + echo $form->field($generator, 'type')->dropDownList($generator->optsType()); + echo $form->field($generator, 'keywords'); + echo $form->field($generator, 'license')->dropDownList($generator->optsLicense(), ['prompt'=>'Choose...']); + echo $form->field($generator, 'title'); + echo $form->field($generator, 'description'); + echo $form->field($generator, 'authorName'); + echo $form->field($generator, 'authorEmail'); + echo $form->field($generator, 'outputPath'); +?> +
diff --git a/extensions/gii/generators/extension/templates/AutoloadExample.php b/extensions/gii/generators/extension/templates/AutoloadExample.php new file mode 100644 index 0000000000..b66b1d1f63 --- /dev/null +++ b/extensions/gii/generators/extension/templates/AutoloadExample.php @@ -0,0 +1,14 @@ + + +namespace namespace, 0, -1) ?>; + +class AutoloadExample extends \yii\base\widget { + function run() { + return "Hello!"; + } +} diff --git a/extensions/gii/generators/extension/templates/README.md b/extensions/gii/generators/extension/templates/README.md new file mode 100644 index 0000000000..c2934943fe --- /dev/null +++ b/extensions/gii/generators/extension/templates/README.md @@ -0,0 +1,35 @@ +title ?> +=== + +description ?> + + +Installation +------------ + +The preferred way to install this extension is through [composer](http://getcomposer.org/download/). + +Either run + +``` +php composer.phar require --prefer-dist vendorName ?>/packageName ?> "*" +``` + +or add + +``` +"vendorName ?>/packageName ?>": "*" +``` + +to the require section of your `composer.json` file. + + +Usage +----- + +Once the extension is installed, simply use it in your code by : + +```php +namespace}\\AutoloadExample::wiget(); ?>" ?> +]; +``` \ No newline at end of file diff --git a/extensions/gii/generators/extension/templates/composer.json b/extensions/gii/generators/extension/templates/composer.json new file mode 100644 index 0000000000..941a9a5d70 --- /dev/null +++ b/extensions/gii/generators/extension/templates/composer.json @@ -0,0 +1,18 @@ +{ + "name": "vendorName ?>/packageName ?>", + "description": "description ?>", + "type": "type ?>", + "keywords": keywordsArrayJson ?>, + "license": "license ?>", + "authors": [ + { + "name": "authorName ?>", + "email": "authorEmail ?>" + } + ], + "autoload": { + "psr-4": { + "namespace) ?>": "" + } + } +} diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 599ec53661..b29456ce12 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -118,9 +118,10 @@ Yii Framework 2 Change Log - Enh #2364: Take into account current error reporting level in error handler (gureedo) - Enh #2387: Added support for fetching data from database in batches (nineinchnick, qiangxue) - Enh #2392: Added `addCssStyle()`, `removeCssStyle()`, `cssStyleFromArray()` and `cssStyleToArray()` to `Html` (qiangxue, kartik-v, Alex-Code) +- Enh #2411: Added Gii extension generator (schmunk42) +- Enh #2415: Added support for inverse relations (qiangxue) - Enh #2417: Added possibility to set `dataType` for `$.ajax` call in yii.activeForm.js (Borales) - Enh #2436: Label of the attribute, which looks like `relatedModel.attribute`, will be received from the related model if it available (djagya) -- Enh #2415: Added support for inverse relations (qiangxue) - Enh #2490: `yii\db\Query::count()` and other query scalar methods now properly handle queries with GROUP BY clause (qiangxue) - Enh #2491: Added support for using the same base class name of search model and data model in Gii (qiangxue) - Enh #2499: Added ability to downgrade migrations by their absolute apply time (resurtm, gorcer)