diff --git a/bin/grav b/bin/grav
index 7c44efd2e..06a55edd8 100755
--- a/bin/grav
+++ b/bin/grav
@@ -17,8 +17,9 @@ if (!file_exists(__DIR__ . '/../vendor')){
}
use Symfony\Component\Console\Application;
+use Grav\Common\Grav;
-require_once __DIR__ . '/../vendor/autoload.php';
+$autoload = require_once __DIR__ . '/../vendor/autoload.php';
if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
@@ -32,15 +33,26 @@ if (!file_exists(ROOT_DIR . 'index.php')) {
exit('FATAL: Must be run from ROOT directory of Grav!');
}
-$app = new Application('Grav CLI Application', '0.1.0');
+if (!function_exists('curl_version')) {
+ exit('FATAL: CLI requires PHP Curl module to be installed');
+}
+
+$grav = Grav::instance(array('loader' => $autoload));
+$grav['config']->init();
+$grav['uri']->init();
+$grav['streams'];
+
+$app = new Application('Grav CLI Application', GRAV_VERSION);
$app->addCommands(array(
- new Grav\Console\Cli\InstallCommand(),
- new Grav\Console\Cli\ComposerCommand(),
- new Grav\Console\Cli\SandboxCommand(),
- new Grav\Console\Cli\CleanCommand(),
- new Grav\Console\Cli\ClearCacheCommand(),
- new Grav\Console\Cli\BackupCommand(),
- new Grav\Console\Cli\NewProjectCommand(),
- new Grav\Console\Cli\NewUserCommand(),
+ new \Grav\Console\Cli\InstallCommand(),
+ new \Grav\Console\Cli\ComposerCommand(),
+ new \Grav\Console\Cli\SandboxCommand(),
+ new \Grav\Console\Cli\CleanCommand(),
+ new \Grav\Console\Cli\ClearCacheCommand(),
+ new \Grav\Console\Cli\BackupCommand(),
+ new \Grav\Console\Cli\NewProjectCommand(),
+ new \Grav\Console\Cli\NewUserCommand(),
+ new \Grav\Console\Cli\DevTools\NewPluginCommand(),
+ new \Grav\Console\Cli\DevTools\NewThemeCommand(),
));
$app->run();
diff --git a/system/src/Grav/Console/Cli/DevTools/DevToolsCommand.php b/system/src/Grav/Console/Cli/DevTools/DevToolsCommand.php
new file mode 100644
index 000000000..07ac4ffc7
--- /dev/null
+++ b/system/src/Grav/Console/Cli/DevTools/DevToolsCommand.php
@@ -0,0 +1,165 @@
+inflector = self::getGrav()['inflector'];
+ $this->locator = self::getGrav()['locator'];
+ }
+ /**
+ *
+ */
+ protected function copyComponent()
+ {
+ $name = $this->component['name'];
+ $folderName = $this->inflector->hyphenize($name);
+ $type = $this->component['type'];
+ $template = $this->component['template'];
+
+
+ $templateFolder = __DIR__ . '/components/' . $type . DS . $template;
+ $componentFolder = $this->locator->findResource($type . 's://') . DS . $folderName;
+
+ Folder::copy($templateFolder, $componentFolder);
+ return;
+ }
+
+ protected function renameComponent()
+ {
+ $name = $this->component['name'];
+ $className = $this->inflector->camelize($name);
+ $folderName = $this->inflector->hyphenize($name);
+ $titleName = $this->inflector->titleize($name);
+ $description = $this->component['description'];
+ $type = $this->component['type'];
+ $template = $this->component['template'];
+
+ unset($this->component['type']);
+ unset($this->component['template']);
+
+ $componentFolder = $this->locator->findResource($type . 's://') . DS . $folderName;
+
+ rename($componentFolder . '/' . $type . '.php' , $componentFolder . DS . $folderName . PLUGIN_EXT);
+ rename($componentFolder . '/' . $type . '.yaml' , $componentFolder . DS . $folderName . YAML_EXT);
+
+ //PHP File
+
+ $data = file_get_contents($componentFolder . DS . $folderName . PLUGIN_EXT);
+
+ $data = str_replace('@@CLASSNAME@@', $className, $data); // @todo dynamic renaming
+ $data = str_replace('@@HYPHENNAME@@', $folderName, $data);
+
+ file_put_contents($componentFolder . DS . $folderName . PLUGIN_EXT, $data);
+
+ //README File
+
+ $data = file_get_contents($componentFolder . DS . 'README.md');
+
+ $data = str_replace('@@NAME@@', $titleName, $data); // @todo dynamic renaming
+ $data = str_replace('@@DESCRIPTION@@', $description, $data);
+
+ file_put_contents($componentFolder . DS . 'README.md', $data);
+
+ //Blueprints File
+ $filename = $componentFolder . '/blueprints' . YAML_EXT;
+ $file = CompiledYamlFile::instance($filename);
+
+ //dump($file);
+
+ $blueprints = new Data\Blueprints($type . 's://');
+ $blueprint = $blueprints->get($folderName . '/blueprints');
+
+ $obj = new Data\Data([], $blueprint);
+ $obj->merge($this->component);
+ $obj->file($file);
+ $obj->save();
+
+ return;
+ }
+
+ /**
+ *
+ */
+ protected function validateOptions()
+ {
+ foreach (array_filter($this->options) as $type => $value) {
+ $this->validate($type, $value);
+ }
+ }
+
+ /**
+ * @param $type
+ * @param $value
+ * @param string $extra
+ *
+ * @return mixed
+ */
+ protected function validate($type, $value, $extra = '')
+ {
+ switch ($type) {
+ case 'name':
+ //Check If name
+ if ($value == null || trim($value) == '') {
+ throw new \RuntimeException('Plugin Name cannot be empty');
+ }
+ // @todo check for existing plugin/theme
+
+ break;
+
+ case 'description':
+ if($value == null || trim($value) == '') {
+ throw new \RuntimeException('Description cannot be empty');
+ }
+
+ break;
+
+ case 'developer':
+ if ($value === null || trim($value) == '') {
+ throw new \RuntimeException('Developer\'s Name cannot be empty');
+ }
+
+ break;
+
+ case 'email':
+ if (!preg_match('/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/', $value)) {
+ throw new \RuntimeException('Not a valid email address');
+ }
+
+ break;
+ }
+
+ return $value;
+ }
+}
diff --git a/system/src/Grav/Console/Cli/DevTools/NewPluginCommand.php b/system/src/Grav/Console/Cli/DevTools/NewPluginCommand.php
new file mode 100644
index 000000000..845cde385
--- /dev/null
+++ b/system/src/Grav/Console/Cli/DevTools/NewPluginCommand.php
@@ -0,0 +1,131 @@
+setName('new-plugin')
+ ->setAliases(['newplugin'])
+ ->addOption(
+ 'name',
+ 'pn',
+ InputOption::VALUE_OPTIONAL,
+ 'The name of your new Grav plugin'
+ )
+ ->addOption(
+ 'description',
+ 'd',
+ InputOption::VALUE_OPTIONAL,
+ 'A description of your new Grav plugin'
+ )
+ ->addOption(
+ 'developer',
+ 'dv',
+ InputOption::VALUE_OPTIONAL,
+ 'The name/username of the developer'
+ )
+ ->addOption(
+ 'email',
+ 'e',
+ InputOption::VALUE_OPTIONAL,
+ 'The developer\'s email'
+ )
+ ->setDescription('Creates a new Grav plugin with the basic required files')
+ ->setHelp('The new-plugin command creates a new Grav instance and performs the creation of a plugin.');
+ }
+
+ /**
+ * @return int|null|void
+ */
+ protected function serve()
+ {
+ $this->init();
+
+ /**
+ * @var array DevToolsCommand $component
+ */
+ $this->component['type'] = 'plugin';
+ $this->component['template'] = 'blank'; // @todo add prompt for template type when more templates are added
+ $this->component['version'] = '0.1.0'; // @todo add optional non prompting version argument
+
+ $this->options = [
+ 'name' => $this->input->getOption('name'),
+ 'description' => $this->input->getOption('description'),
+ 'author' => [
+ 'name' => $this->input->getOption('developer'),
+ 'email' => $this->input->getOption('email')
+ ]
+ ];
+
+ $this->validateOptions();
+
+ $this->component = array_replace($this->component, $this->options);
+
+ $helper = $this->getHelper('question');
+
+ if (!$this->options['name']) {
+ $question = new Question('Enter Plugin Name: ');
+ // @todo set validator
+
+ $this->component['name'] = $helper->ask($this->input, $this->output, $question);
+ }
+
+ if (!$this->options['description']) {
+ $question = new Question('Enter Plugin Description: ');
+ // @todo set validator
+
+ $this->component['description'] = $helper->ask($this->input, $this->output, $question);
+ }
+
+ if (!$this->options['author']['name']) {
+ $question = new Question('Enter Developer Name: ');
+ // @todo set validator
+
+ $this->component['author']['name'] = $helper->ask($this->input, $this->output, $question);
+ }
+
+ if (!$this->options['author']['email']) {
+ $question = new Question('Enter Developer Email: ');
+ // @todo set validator
+
+ $this->component['author']['email'] = $helper->ask($this->input, $this->output, $question);
+ }
+ $this->copyComponent();
+ $this->renameComponent();
+ }
+
+}
diff --git a/system/src/Grav/Console/Cli/DevTools/NewThemeCommand.php b/system/src/Grav/Console/Cli/DevTools/NewThemeCommand.php
new file mode 100644
index 000000000..a2bba5185
--- /dev/null
+++ b/system/src/Grav/Console/Cli/DevTools/NewThemeCommand.php
@@ -0,0 +1,143 @@
+setName('new-theme')
+ ->setAliases(['newtheme'])
+ ->addOption(
+ 'name',
+ 'pn',
+ InputOption::VALUE_OPTIONAL,
+ 'The name of your new Grav theme'
+ )
+ ->addOption(
+ 'description',
+ 'd',
+ InputOption::VALUE_OPTIONAL,
+ 'A description of your new Grav theme'
+ )
+ ->addOption(
+ 'developer',
+ 'dv',
+ InputOption::VALUE_OPTIONAL,
+ 'The name/username of the developer'
+ )
+ ->addOption(
+ 'email',
+ 'e',
+ InputOption::VALUE_OPTIONAL,
+ 'The developer\'s email'
+ )
+ ->setDescription('Creates a new Grav theme with the basic required files')
+ ->setHelp('The new-theme command creates a new Grav instance and performs the creation of a theme.');
+ }
+
+ /**
+ * @return int|null|void
+ */
+ protected function serve()
+ {
+ $this->init();
+ $this->gpm = new GPM(true);
+
+ /**
+ * @var array DevToolsCommand $component
+ */
+ $this->component['type'] = 'theme';
+ $this->component['template'] = 'blank'; // @todo add prompt for template type when more templates are added
+ $this->component['version'] = '0.1.0'; // @todo add optional non prompting version argument
+
+ $this->options = [
+ 'name' => $this->input->getOption('name'),
+ 'description' => $this->input->getOption('description'),
+ 'author' => [
+ 'name' => $this->input->getOption('developer'),
+ 'email' => $this->input->getOption('email')
+ ]
+ ];
+
+ $this->validateOptions();
+
+ $this->component = array_replace($this->component, $this->options);
+
+ $helper = $this->getHelper('question');
+
+ if (!$this->options['name']) {
+ $question = new Question('Enter Theme Name: ');
+ // @todo set validator
+
+ $this->component['name'] = $helper->ask($this->input, $this->output, $question);
+ }
+
+ if (!$this->options['description']) {
+ $question = new Question('Enter Theme Description: ');
+ // @todo set validator
+
+ $this->component['description'] = $helper->ask($this->input, $this->output, $question);
+ }
+
+ if (!$this->options['author']['name']) {
+ $question = new Question('Enter Developer Name: ');
+ // @todo set validator
+
+ $this->component['author']['name'] = $helper->ask($this->input, $this->output, $question);
+ }
+
+ if (!$this->options['author']['email']) {
+ $question = new Question('Enter Developer Email: ');
+ // @todo set validator
+
+ $this->component['author']['email'] = $helper->ask($this->input, $this->output, $question);
+ }
+
+ if ($this->component['template'] == 'blank') {
+ //$themesObject = self::getGrav()['themes'];
+ $themes = $this->gpm->getInstalledThemes();
+ $installedThemes = [];
+ foreach($themes as $key => $theme) {
+ array_push($installedThemes, $key);
+ }
+ $question = new ChoiceQuestion(
+ 'Please choose a theme to extend: ',
+ $installedThemes
+ );
+ //dump($this->gpm->getInstalledThemes());
+ $this->component['extends'] = $helper->ask($this->input, $this->output, $question);
+ }
+ //$this->copyComponent();
+ //$this->renameComponent();
+ }
+
+}
diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/CHANGELOG.md b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/CHANGELOG.md
new file mode 100644
index 000000000..e69de29bb
diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/LICENSE b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/LICENSE
new file mode 100644
index 000000000..e69de29bb
diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/README.md b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/README.md
new file mode 100644
index 000000000..430e28152
--- /dev/null
+++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/README.md
@@ -0,0 +1,5 @@
+# @@NAME@@
+
+The **@@NAME@@** Plugin is for [Grav](http://github.com/getgrav/grav)
+
+@@DESCRIPTION@@
diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/blueprints.yaml b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/blueprints.yaml
new file mode 100644
index 000000000..62f8b012b
--- /dev/null
+++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/blueprints.yaml
@@ -0,0 +1,3 @@
+cosgrove: "my field"
+form:
+ validation: loose
diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.php b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.php
new file mode 100644
index 000000000..f0bb239b4
--- /dev/null
+++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.php
@@ -0,0 +1,90 @@
+ ['onPluginsInitialized', 0]
+ ];
+ }
+
+ /**
+ * Initialize the plugin
+ */
+ public function onPluginsInitialized()
+ {
+ if ($this->grav['config']->get('plugins.@@HYPHENNAME@@.enabled')) { // Check if enabled in configuration.
+
+ $this->active = true; // Set's the plugin state to active.
+
+ $this->enable([
+ 'onPageInitialized' => ['onPageInitialized', 0] // Adds the onPageInitialized event listener
+ ]);
+ }
+
+ }
+
+ /**
+ * Does something with pages
+ */
+ public function onPageInitialized()
+ {
+ // Exit the function if plugin is not active
+ if (!$this->active){
+ return;
+ }
+
+ // Do things with the page
+ $somevariable = $this->returnTrue(); // Call a protected function and set a variable to it's value
+
+ $this->doSomeProcesses(); // Call a protected function that runs some processes
+ }
+
+ protected function returnTrue()
+ {
+ return true;
+ }
+
+ protected function doSomeProcesses()
+ {
+ // Generate a random 10 letter string
+ $result = "";
+ $chars = "abcdefghijklmnopqrstuvwxyz";
+ $charArray = str_split($chars);
+ for($i = 0; $i < 10; $i++){
+ $randItem = array_rand($charArray);
+ $result .= "".$charArray[$randItem];
+ }
+
+ // Do some math
+ $two = 8*4;
+ $twentyone = 7*3; // anyone up for poker?
+ }
+}
diff --git a/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.yaml b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.yaml
new file mode 100644
index 000000000..d4ca94189
--- /dev/null
+++ b/system/src/Grav/Console/Cli/DevTools/components/plugin/blank/plugin.yaml
@@ -0,0 +1 @@
+enabled: true