Source of file RoboFile.php

Size: 10,018 Bytes - Last Modified: 2019-05-22T08:51:12+00:00

/home/matic/hprojects/public-docs/intrigo-plugin-box/src/RoboFile.php

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
<?php

declare(strict_types=1);
require_once 'vendor/autoload.php';


/**
 * This is project's console commands configuration for Robo task runner.
 *
 * @see http://robo.li/
 */
class RoboFile extends \Robo\Tasks
{
	use Robo\Task\Base\loadShortcuts;

	/**
	 * Relative path to config folder of source module.
	 *
	 * @var string
	 */
	const REFINE_IT_CONFIG_PATH = './RefineIt/config/';

	/**
	 * Relative path to code templates.
	 *
	 * @var string
	 */
	const CODE_FOLDER_PATH = '../code/';

	/**
	 * Relative path to root directory for all modules.
	 *
	 * @var string
	 */
	const MODULE_BASE_PATH = './';

	/**
	 * Relative path to source module.
	 *
	 * @var string
	 */
	const SOURCE_MODULE_PATH = './RefineIt/';

	/**
	 * Relative path to ipb-info.json file - contains basic information to enable use of code templates.
	 *
	 * @var string
	 */
	const IPB_INFO_FILE = './.ipb-info.json';

	/**
	 * Holder of configuration required for this class to function.
	 * 
	 * @var array
	 */
	private $config;

	/**
	 * Code templates loader.
	 * 
	 * @var \Twig\Loader\FilesystemLoader
	 */
	private $loader;

	/**
	 * Code templates environments,
	 * 
	 * @var \Twig\Environment
	 */
	private $env;

	/**
	 * Constructor.
	 */
	function __construct() {
		// For this class to be useful we only really need structure.php and context.php
		$this->config = [
			'structure' => include(__DIR__ . '/' . self::REFINE_IT_CONFIG_PATH . 'structure' . '.php'),
			'context' => include(__DIR__ . '/' . self::REFINE_IT_CONFIG_PATH . 'context' . '.php')
		];

		$this->loader = new \Twig\Loader\FilesystemLoader(realpath(self::CODE_FOLDER_PATH));
		$this->env = new \Twig\Environment($this->loader);
	}

	/**
	 * Duplicates source module in destination.
	 * 
	 * @param  string $source      Absolute path to root of module.
	 * @param  string $destination Absolute path to root of destination where we want new module to be.
	 * @return void
	 */
	private function copyDir(string $source, string $destination): void {
		$dir = opendir($source);
		@mkdir($destination);
		while(false !== ( $file = readdir($dir)) ) {
			if (( $file != '.' ) && ( $file != '..' )) {
				if ( is_dir($source . '/' . $file)) {
					$this->copyDir($source . '/' . $file,  $destination . '/' . $file);
				}
				else if (!is_dir($source . '/' . $file)) {
					copy($source . '/' . $file, $destination . '/' . $file);
				}
			}

		}
		closedir($dir);
	}

	/**
	 * Checks file existance before generating new file.
	 * 
	 * @param  string       $template    Filename from CODE_FOLDER_PATH directory.
	 * @param  array        $data        Values to use in template.
	 * @param  string       $destination Absolute path to new file.
	 * @param  bool|boolean $override    If set tu true method will overwrite file in case it exists. Default: false
	 * @return string                    Returns one of the following strings: [FILE_ALREADY_EXISTS, FILE_CREATED] accordingly.
	 */
	private function generateFile(string $template, array $data, string $destination, bool $override=false): string {
		if (file_exists($destination) && !$override) {
			$this->say("It appears that file: " . $destination . " already exists. Exiting.");
			return 'FILE_ALREADY_EXISTS';
		}

		file_put_contents(
			$destination,
			$this->env->render(
				$template,
				$data
		));

		return 'FILE_CREATED';
	}

	/**
	 * Generates plugin main filename based on plugin name.
	 * 
	 * @param  string $s Plugin name.
	 * @return string    Name of the file or string 'n-a' if value could not be slugified.
	 */
	private function slugify(string $s): string {
		$s = preg_replace('~[^\pL\d]+~u', '-', $s);
		$s = iconv('utf-8', 'us-ascii//TRANSLIT', $s);
		$s = preg_replace('~[^-\w]+~', '', $s);
		$s = trim($s, '-');
		$s = preg_replace('~-+~', '-', $s);
		$s = strtolower($s);

		if (empty($s)) {
		  return 'n-a';
		}

		return $s;
	}

	/**
	 * Generates string containing all the mdoules.
	 * 
	 * @param  array  $modules List of modules to load.
	 * @return string String suitable to use in templates.
	 */
	private function getLoadModulesString(array $modules): string {
		$load_modules = '';
		foreach ($modules as $namespace_name) {
			$load_modules .= $this->env->render(
				'snippet-active-module.txt', 
				['namespace_name' => $namespace_name]
			);
		}

		return $load_modules;
	}

	/**
	 * Asks for basic info about the plugin.
	 *
	 * Every Wordpress plugin needs to have header in main file. Values that need to be in 
	 * this header are specified with this command.
	 * 
	 * @return void
	 * @command begin
	 */
	function begin(): void {
		if (file_exists(self::IPB_INFO_FILE)) {
			$this->say("File: " . self::IPB_INFO_FILE . " found. Exiting.");
			return;
		}

		$this->say("Let's set some parameters, so you can focus on writing amazing plugin.");

		$info = [
			'plugin_name' 			=> [
				'question'	=> "Plugin Name",
				'value'		=> "Intrigo Plugin Box"
			],

			'plugin_uri'			=> [
				"question"	=> "Plugin URI",
				'value'		=> "https://gitlab.com/Zag/intrigo-plugin-box"
			],
			'plugin_description'	=> [
				'question'		=> "Description",
				'value'			=> "Another way of building Wordpress plugins."
			],
			'plugin_version'		=> [
				'question'		=> "Version",
				'value'			=> "v0.0.0"
			],
			'plugin_author'			=> [
				'question'		=> "Author",
				'value'			=> "Matic Zagmajster"
			],
			'plugin_author_uri'		=> [
				'question'		=> "Author URI",
				'value'			=> "http://maticzagmajster.ddns.net/"
			]
		];

		foreach ($info as $prop => $sub) {
			$value = $this->ask($sub['question'] . " (Default: " . $sub['value'] . ") INPUT: ");
			if ($value !== NULL) {
				$info[$prop]['value'] = $value;
			}
		}

		$content = [];
		foreach ($info as $prop => $sub) {
			$content[$prop] = $sub['value'];
		}
		$content['load_modules'] = [];
		$json_data = json_encode($content, JSON_PRETTY_PRINT);
		file_put_contents(self::IPB_INFO_FILE, $json_data);

		// Generate main plugin file.
		$content['load_modules'] = '';
		$destination = realpath(self::MODULE_BASE_PATH) . '/' . $this->slugify($content['plugin_name']) . '.php';
		$status = $this->generateFile('index.php', $content, $destination);

		if ($status == 'FILE_CREATED') {
			$this->say("Main plugin file was created: " . $destination);
		}

	}

	/**
	 * Generates new module.
	 * 
	 * @param  string $namespace_name Name of new module.
	 * @return void
	 * @command: module:create
	 */
	function moduleCreate(string $namespace_name): void {
		$source_module_path = realpath(self::SOURCE_MODULE_PATH);
		$destination_module_path = realpath(self::MODULE_BASE_PATH) . '/' . $namespace_name;

		if (file_exists($destination_module_path)) {
			$this->say("It appears this module already exists. Exiting.");
			return;
		}

		$this->copyDir($source_module_path, $destination_module_path);

		// Some elements are required just in RefineIt module and others are using template.
		$remove_elements = [
			$this->config['structure']['config_folder']['name'] . '/' . $this->config['structure']['config_folder']['children']['structure_file']['name'],
			$this->config['structure']['support_folder']['name']
		];

		$files_from_templates = [
			$this->config['structure']['info_file']['name'],
			$this->config['structure']['plugin_shell_file']['name']
		];

		$remove_elements = array_merge($remove_elements, $files_from_templates);

		foreach ($remove_elements as $relative) {
			$path = $destination_module_path . '/' . $relative;
			$this->_exec('rm -rf ' . $path);
		}

		foreach ($files_from_templates as $file) {
			$destination = $destination_module_path . '/' . $file;
			file_put_contents($destination, $this->env->render($file, ['namespace_name' => $namespace_name]));
		}

		$this->say("New module: " . $namespace_name . " created!");
	}

	/**
	 * Creates new model inside given module.
	 * 
	 * @param  string $namespace_name Name of the module.
	 * @param  string $model_name     Name of the model.
	 * @return void
	 * @command model:create
	 */
	function modelCreate(string $namespace_name, string $model_name): void {
		$destination = realpath(self::MODULE_BASE_PATH) . '/' . $namespace_name . '/' . $this->config['structure']['models_folder']['name'] . '/' . $model_name . '.php';

		$status = $this->generateFile(
			'Model.php',
			['namespace_name' => $namespace_name, 'model_name' => $model_name],
			$destination
		);
		if ($status == 'FILE_ALREADY_EXISTS') {
			return;
		}

		$out = $namespace_name . '\\' . $this->config['structure']['models_folder']['name'] . '\\' . $model_name;
		$this->say("New model: " . $out . " was created.");
	}

	/**
	 * Creates new controller inside given module.
	 * 
	 * @param  string $namespace_name  Name of the module.
	 * @param  string $controller_name Name of the controller.
	 * @return void
	 * @command controller:create
	 */
	function controllerCreate(string $namespace_name, string $controller_name): void {
		$destination = realpath(self::MODULE_BASE_PATH) . '/' . $namespace_name . '/' . $this->config['structure']['controllers_folder']['name'] . '/' . $controller_name . '.php';
		
		$status = $this->generateFile('Controller.php', ['namespace_name' => $namespace_name, 'controller_name' => $controller_name], $destination);
		if ($status == 'FILE_ALREADY_EXISTS') {
			return;
		}

		$out = $namespace_name . '\\' . $this->config['structure']['controllers_folder']['name'] . '\\' . $controller_name;
		$this->say("New controller: " . $out . " was created.");
	}

	/**
	 * Creates plugin main file.
	 * 
	 * @return void
	 * @command plugin:create
	 */
	function pluginCreate(): void {
		// Load data.
		$content = json_decode(file_get_contents(self::IPB_INFO_FILE), true);
		$content['load_modules'] = $this->getLoadModulesString($content['load_modules']);

		// Regenerate main plugin file.
		$destination = realpath(self::MODULE_BASE_PATH) . '/' . $this->slugify($content['plugin_name']) . '.php';
		$this->generateFile('index.php', $content, $destination, true);

		$this->say("Main plugin file was created: " . $destination);
	}

}