diff --git a/.gitignore b/.gitignore
index 9158548..569df28 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,4 +34,4 @@ phpunit.phar
# vagrant runtime
/.vagrant
/artweb/
-/storage
+/storage
\ No newline at end of file
diff --git a/Initializer.php b/Initializer.php
new file mode 100644
index 0000000..5e3ffeb
--- /dev/null
+++ b/Initializer.php
@@ -0,0 +1,1037 @@
+defineEnvironment();
+ $instance->startInitialization();
+ if ($instance->askInitDb()) {
+ $instance->defineDb();
+ $instance->migrate();
+ $instance->createUser();
+ $instance->congratulate();
+ }
+ }
+
+ /**
+ * Get instance of Initializer
+ *
+ * @return mixed
+ */
+ public static function getInstance(): Initializer
+ {
+ if (empty( self::$instance )) {
+ self::$instance = new self();
+ }
+ return self::$instance;
+ }
+
+ /**
+ * Initializer private constructor. You can get Singleton with getInstance()
+ *
+ * Availiable options:
+ * * --env - One of available environments
+ * * --overwrite - Do overwrite all files without confirmation
+ * * --dbinit - Initialize database after app initialization
+ * * --dbtype - Database type. Available: postgresql, mysql
+ * * --host - Database host, default to 127.0.0.1
+ * * --port - Database port used by postgresql, default to 5432
+ * * --schema - Database schema for postresql, default to public
+ * * --dbname - Database name, required
+ * * --username - Database username, required
+ * * --password - Database password, required
+ * * --migrationPath - Migration path, default to vendor/artweb/artbox-core/migrations
+ * * --migrate - Whether to migrate, default to apply, set no to skip migration
+ * * --user_username - Username for user creation
+ * * --user_email - Email for user creation
+ * * --user_password - Password for user creation
+ * * --user - Whether to create user, default to yes, set no to skip creation
+ * * --defaultuser - Whether to use default user creation
+ * * --o - Webpage to open after intallaction process
+ *
+ * @see Initializer::getInstance()
+ */
+ private function __construct()
+ {
+ echo $this->formatMessage(
+ "\tArtbox Application Initialization Tool v" . self::VERSION,
+ [ 'bold' ]
+ ) . "\n\n";
+ }
+
+ /**
+ * Define environment for an application
+ *
+ * @return string
+ */
+ private function defineEnvironment()
+ {
+ $envName = $this->getParamValue('env');
+ $envs = $this->getEnvironmentNames();
+ if (empty( $envName ) || $envName === '1') {
+ do {
+ $envName = $this->askEnvironment($envs);
+ echo "\n Initialize the application under '{$envName}' environment? [yes|no] ";
+ $answer = trim(fgets(STDIN));
+ } while (strncasecmp($answer, 'y', 1));
+ } else {
+ if (!in_array($envName, $envs)) {
+ $this->printError("Wrong environment name, available list: " . implode(', ', $envs));
+ exit( 1 );
+ }
+ }
+ $this->environment = $this->envs[ $envName ];
+ return $this->environment;
+ }
+
+ /**
+ * Start actual application initialization with files overwriting
+ */
+ private function startInitialization()
+ {
+ echo "\n Start initialization\n";
+ echo " =====================\n";
+
+ $this->rewriteFiles();
+ $this->callback();
+ echo "\n App initialization completed\n";
+ echo " ==============================\n";
+ }
+
+ /**
+ * Ask whether to init databse. If dbinit param is set, this step will be skipped.
+ *
+ * @return bool
+ */
+ private function askInitDb(): bool
+ {
+ echo " Start database initialization\n";
+ $params = $this->getParams();
+ if (!isset( $params[ 'dbinit' ] )) {
+ do {
+ echo $this->formatMessage("\n Init the database? [yes|no] ", [ 'bold' ]);
+ $answer = trim(fgets(STDIN));
+ } while (( strncasecmp($answer, 'y', 1) !== 0 ) && ( strncasecmp($answer, 'n', 1) !== 0 ));
+ if (strncasecmp($answer, 'n', 1) == 0) {
+ $this->noDatabaseMessage();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Define which database driver to use. Available options: postgresql, mysql
+ */
+ private function defineDb()
+ {
+ $params = $this->getParams();
+ if (isset( $params[ 'dbinit' ] )) {
+ $this->validateConnection();
+ } else {
+ $answer = '';
+ do {
+ if (!empty( $answer )) {
+ $this->printError("Incorrect database type. Try again or write 'quit' to exit");
+ }
+ echo "\n Which database do you want to use? [postgresql|mysql] ";
+ $answer = trim(fgets(STDIN));
+
+ } while (( strncasecmp($answer, 'q', 1) !== 0 ) && ( !in_array(
+ $answer,
+ [
+ 'postgresql',
+ 'mysql',
+ 'p',
+ 'm',
+ ]
+ ) ));
+ if (strncasecmp($answer, 'q', 1) === 0) {
+ $this->noDatabaseMessage();
+ }
+ if (strncasecmp($answer, 'p', 1) === 0) {
+ $answer = 'postgresql';
+ } else {
+ $answer = 'mysql';
+ }
+ if ($answer == 'postgresql') {
+ $this->initPostgres();
+ } else {
+ $this->initMysql();
+ }
+ }
+ $this->initDb();
+ }
+
+ /**
+ * Get parsed params
+ *
+ * @see Initializer::parseParams()
+ *
+ * @return array
+ */
+ private function getParams(): array
+ {
+ if (empty( $this->params )) {
+ $this->parseParams();
+ }
+ return $this->params;
+ }
+
+ /**
+ * Get params from input string
+ * For example
+ *
+ * **php init test --param1=value1 --param2=value2
**
+ *
+ * will get
+ *
+ * **
+ * [
+ * test,
+ * value1,
+ * value2
+ * ]
+ *
+ *
+ * @return array
+ */
+ private function parseParams(): array
+ {
+ $rawParams = [];
+ if (isset( $_SERVER[ 'argv' ] )) {
+ $rawParams = $_SERVER[ 'argv' ];
+ array_shift($rawParams);
+ }
+
+ $params = [];
+ foreach ($rawParams as $param) {
+ if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
+ $name = $matches[ 1 ];
+ $params[ $name ] = isset( $matches[ 3 ] ) ? $matches[ 3 ] : true;
+ } else {
+ $params[] = $param;
+ }
+ }
+ $this->params = $params;
+ return $this->params;
+ }
+
+ /**
+ * Get value of input param. Empty string if not exist.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ private function getParamValue(string $name): string
+ {
+ $params = $this->getParams();
+ if (isset( $params[ $name ] ) && !empty( $params[ $name ] )) {
+ return $params[ $name ];
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Get project root directory according to file system
+ *
+ * @return mixed
+ */
+ private function getRoot(): string
+ {
+ if (empty( $this->root )) {
+ $this->root = str_replace('\\', '/', __DIR__);
+ }
+ return $this->root;
+ }
+
+ /**
+ * Get available environments from environments/index.php file
+ *
+ * Follow environments/index.php manifest to create your own environments
+ *
+ * @return array
+ */
+ private function getEnvironments(): array
+ {
+ $path = "{$this->getRoot()}/environments/index.php";
+ if (empty( $this->envs )) {
+ /** @noinspection PhpIncludeInspection */
+ $this->envs = require( $path );
+ }
+ if (empty( $this->envs )) {
+ die( "There are no available environments in $path" );
+ }
+ return $this->envs;
+ }
+
+ /**
+ * Get environment names
+ *
+ * @return array
+ */
+ private function getEnvironmentNames(): array
+ {
+ return array_keys($this->getEnvironments());
+ }
+
+ /**
+ * Show user variants to choose environment from
+ *
+ * @param array $envs
+ *
+ * @return string
+ */
+ private function askEnvironment(array $envs): string
+ {
+ echo "Which environment do you want the application to be initialized in?\n\n";
+ foreach ($envs as $i => $name) {
+ echo " [$i] $name\n";
+ }
+ $answer = $this->offerEnvironment(count($envs));
+ while (!( ( ctype_digit($answer) && in_array($answer, range(0, count($envs) - 1)) ) || $answer === 'q' )) {
+ $answer = $this->offerEnvironment(count($envs));
+ }
+ if ($answer === 'q') {
+ echo "\n Quit initialization.\n";
+ exit( 0 );
+ } else {
+ if (isset( $envs[ $answer ] )) {
+ $envName = $envs[ $answer ];
+ } else {
+ die( "Error while trying to get environment name. Try another one." );
+ }
+ }
+ return $envName;
+ }
+
+ /**
+ * Offer user to choose environment number
+ *
+ * @param int $count
+ *
+ * @return string
+ */
+ private function offerEnvironment(int $count): string
+ {
+ echo "\n Your choice [0-" . ( $count - 1 ) . ', or "q" to quit] ';
+ return trim(fgets(STDIN));
+ }
+
+ /**
+ * Rewrite files by files in environments/$environment['path']
+ */
+ private function rewriteFiles()
+ {
+ $environment = $this->environment;
+ $root = $this->getRoot();
+ if (isset( $environment[ 'path' ] ) && !empty( $environment[ 'path' ] )) {
+ $path = $environment[ 'path' ];
+ } else {
+ $this->printError('Environment configuration failed. Please set path value.');
+ exit( 1 );
+ }
+ $files = $this->getFileList("$root/environments/$path");
+ if (isset( $environment[ 'skipFiles' ] )) {
+ $skipFiles = $environment[ 'skipFiles' ];
+ array_walk(
+ $skipFiles,
+ function (&$value) use ($root) {
+ $value = "$root/$value";
+ }
+ );
+ $files = array_diff(
+ $files,
+ array_intersect_key(
+ $environment[ 'skipFiles' ],
+ array_filter($skipFiles, 'file_exists')
+ )
+ );
+ }
+ $all = false;
+ foreach ($files as $file) {
+ if (!$this->copyFile("environments/{$path}/$file", $file, $all)) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Recursively get all files from $root directory.
+ *
+ * This will ignore .git, .svn directories.
+ *
+ * @param string $root
+ * @param string $basePath
+ *
+ * @return array
+ */
+ private function getFileList(string $root, string $basePath = ''): array
+ {
+ $files = [];
+ $handle = opendir($root);
+ while (( $path = readdir($handle) ) !== false) {
+ if ($path === '.git' || $path === '.svn' || $path === '.' || $path === '..') {
+ continue;
+ }
+ $fullPath = "$root/$path";
+ $relativePath = $basePath === '' ? $path : "$basePath/$path";
+ if (is_dir($fullPath)) {
+ $files = array_merge($files, $this->getFileList($fullPath, $relativePath));
+ } else {
+ $files[] = $relativePath;
+ }
+ }
+ closedir($handle);
+ return $files;
+ }
+
+ /**
+ * Run callbacks for application initialization
+ */
+ private function callback()
+ {
+ $environment = $this->environment;
+ foreach (self::CALLBACKS as $callback) {
+ if (!empty( $environment[ $callback ] )) {
+ $this->$callback($environment[ $callback ]);
+ }
+ }
+ }
+
+ /**
+ * Set directories in $environment['setWrotable'] to chmod 0777
+ *
+ * @param $paths
+ */
+ private function setWritable(array $paths)
+ {
+ $root = $this->getRoot();
+ foreach ($paths as $writable) {
+ $fullPath = "$root/$writable";
+ if (is_dir($fullPath)) {
+ if (@chmod($fullPath, 0777)) {
+ echo $this->formatMessage(
+ " ***** Set writable $writable (chmod 0777)",
+ [ 'fg-yellow' ]
+ ) . "\n";
+ } else {
+ $this->printError("Operation chmod not permitted for directory $writable.");
+ }
+ } else {
+ if (!@mkdir($fullPath, 0777, true)) {
+ $this->printError("Directory $writable does not exist and cannot be created.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Set files in $environment['setExecutable'] to chmod 0755
+ *
+ * @param $paths
+ */
+ private function setExecutable(array $paths)
+ {
+ $root = $this->getRoot();
+ foreach ($paths as $executable) {
+ $fullPath = "$root/$executable";
+ if (file_exists($fullPath)) {
+ if (@chmod($fullPath, 0755)) {
+ echo $this->formatMessage(" ***** Set executable $executable (chmod 0755)") . "\n";
+ } else {
+ $this->printError("Operation chmod not permitted for $executable.");
+ }
+ } else {
+ $this->printError("$executable does not exist.");
+ }
+ }
+ }
+
+ /**
+ * Set cookie validation keys to files in $environment['setCookieValidationKey'].
+ *
+ * @param $paths
+ */
+ private function setCookieValidationKey(array $paths)
+ {
+ $root = $this->getRoot();
+ foreach ($paths as $file) {
+ echo $this->formatMessage(
+ " ***** Generate cookie validation key in $file",
+ [
+ 'bold',
+ 'fg-magenta',
+ ]
+ ) . "\n";
+ $file = $root . '/' . $file;
+ $length = 32;
+ $bytes = openssl_random_pseudo_bytes($length);
+ $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
+ $this->setParam('cookieValidationKey', $key, $file);
+ }
+ }
+
+ private function createSymlink(array $links)
+ {
+ $root = $this->getRoot();
+ foreach ($links as $link => $target) {
+ //first removing folders to avoid errors if the folder already exists
+ @rmdir($root . "/" . $link);
+ //next removing existing symlink in order to update the target
+ if (is_link($root . "/" . $link)) {
+ @unlink($root . "/" . $link);
+ }
+ if (@symlink($root . "/" . $target, $root . "/" . $link)) {
+ echo $this->formatMessage(" ***** Symlink $root/$target $root/$link", [ 'fg-blue' ]) . "\n";
+ } else {
+ $this->printError("Cannot create symlink $root/$target $root/$link.");
+ }
+ }
+ }
+
+ /**
+ * Copy file from environment directory to project directory
+ *
+ * @param string $source Environment source file path
+ * @param string $target Project file path target
+ * @param bool $all Rewrite all flag
+ *
+ * @return bool
+ */
+ private function copyFile(string $source, string $target, bool &$all)
+ {
+ $root = $this->getRoot();
+ $params = $this->getParams();
+ if (!is_file($root . '/' . $source)) {
+ echo $this->formatMessage(" ----- skip $target ($source not exist)", [ 'fg-cyan' ]) . "\n";
+ return true;
+ }
+ if (is_file($root . '/' . $target)) {
+ if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
+ echo $this->formatMessage(" ----- unchanged $target", [ 'fg-cyan' ]) . "\n";
+ return true;
+ }
+ if ($all) {
+ echo $this->formatMessage(" ----- overwrite $target", [ 'fg-blue' ]) . "\n";
+ } else {
+ echo $this->formatMessage(" -- exist $target", [ 'fg-magenta' ]) . "\n";
+ echo " overwrite? [Yes|No|All|Quit] ";
+
+ $answer = !empty( $params[ 'overwrite' ] ) ? $params[ 'overwrite' ] : trim(fgets(STDIN));
+ echo "\n";
+ if (!strncasecmp($answer, 'q', 1)) {
+ return false;
+ } else {
+ if (!strncasecmp($answer, 'y', 1)) {
+ echo $this->formatMessage(" ----- overwrite $target", [ 'fg-blue' ]) . "\n";
+ } else {
+ if (!strncasecmp($answer, 'a', 1)) {
+ echo $this->formatMessage(" ----- overwrite $target", [ 'fg-blue' ]) . "\n";
+ $all = true;
+ } else {
+ echo $this->formatMessage(
+ " ----- skip $target ($source not exist)",
+ [ 'fg-cyan' ]
+ ) . "\n";
+ return true;
+ }
+ }
+ }
+ }
+ file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
+ return true;
+ }
+ echo "\n" . $this->formatMessage(" ----- generate $target", [ 'fg-green' ]) . "\n";
+ @mkdir(dirname($root . '/' . $target), 0777, true);
+ file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
+ return true;
+ }
+
+ /**
+ * Set param in file to particular value.
+ *
+ * For example: setParam('param', 'value', 'config.php') will replace content in config.php
+ *
+ * from
+ *
+ * 'param' => ''
+ *
+ * to
+ *
+ * 'param' => 'value'
+ *
+ * @param string $param
+ * @param string $value
+ * @param string $file
+ * @param bool $noQuote
+ * @param bool $force
+ * @param bool $alternate
+ */
+ private function setParam(
+ string $param,
+ string $value,
+ string $file,
+ bool $noQuote = false,
+ bool $force = false,
+ bool $alternate = false
+ ) {
+ if ($alternate) {
+ $regexp = '/(("|\')db("|\')\s*=>\s*)(.*|.*)/';
+ } else {
+ if ($force) {
+ $regexp = '/(("|\')' . $param . '("|\')\s*=>\s*)(".*"|\'.*\')/';
+ } else {
+ $regexp = '/(("|\')' . $param . '("|\')\s*=>\s*)(""|\'\')/';
+ }
+ }
+ if ($noQuote) {
+ $content = preg_replace(
+ $regexp,
+ "\\1$value",
+ file_get_contents($file)
+ );
+ } else {
+ $content = preg_replace(
+ $regexp,
+ "\\1'$value'",
+ file_get_contents($file)
+ );
+ }
+ file_put_contents($file, $content);
+ }
+
+ /**
+ * Init postgres connection
+ *
+ * @return array
+ */
+ private function initPostgres(): array
+ {
+ $db = [
+ 'dbtype' => 'postgresql',
+ ];
+ echo "\n Enter your database host: ";
+ $host = trim(fgets(STDIN));
+ echo "\n Enter your database port: ";
+ $port = trim(fgets(STDIN));
+ echo "\n Enter your database schema: ";
+ $db[ 'schema' ] = trim(fgets(STDIN));
+ echo "\n Enter your database name: ";
+ $name = trim(fgets(STDIN));
+ echo "\n Enter your database username: ";
+ $db[ 'username' ] = trim(fgets(STDIN));
+ echo "\n Enter your database password: ";
+ $db[ 'password' ] = trim(fgets(STDIN));
+ $db[ 'dsn' ] = "pgsql:host={$host};port={$port};dbname={$name}";
+ $this->db = $db;
+ return $db;
+ }
+
+ /**
+ * Init mysql connection
+ *
+ * @return array
+ */
+ private function initMysql(): array
+ {
+ $db = [
+ 'dbtype' => 'mysql',
+ ];
+ echo "\n Enter your database host: ";
+ $host = trim(fgets(STDIN));
+ echo "\n Enter your database name: ";
+ $name = trim(fgets(STDIN));
+ echo "\n Enter your database username: ";
+ $db[ 'username' ] = trim(fgets(STDIN));
+ echo "\n Enter your database password: ";
+ $db[ 'password' ] = trim(fgets(STDIN));
+ $db[ 'dsn' ] = "mysql:host={$host};dbname={$name}";
+ $this->db = $db;
+ return $db;
+ }
+
+ /**
+ * Validate non-interactive db data and fill it for further actions.
+ *
+ * @return array
+ */
+ private function validateConnection(): array
+ {
+ $db = [];
+ $dbType = strtolower($this->getParamValue('dbtype'));
+ if ($dbType !== 'postgresql' && $dbType !== 'mysql') {
+ die( "Supported DB types are postgresql and mysql" );
+ }
+ if ($dbType === 'postgresql') {
+ $host = $this->getParamValue('host') ? : '127.0.0.1';
+ $port = $this->getParamValue('port') ? : '5432';
+ $db[ 'schema' ] = $this->getParamValue('schema') ? : 'public';
+ $name = $this->getParamValue('dbname');
+ if (empty( $name )) {
+ die( "Database name must be set" );
+ }
+ $db[ 'dsn' ] = "pgsql:host={$host};port={$port};dbname={$name}";
+ if (empty( $username = $this->getParamValue('username') )) {
+ die( "Database username must be set" );
+ }
+ $db[ 'username' ] = $username;
+ if (empty( $password = $this->getParamValue('password') )) {
+ die( "Database password must be set" );
+ }
+ $db[ 'password' ] = $password;
+ } else {
+ $host = $this->getParamValue('host') ? : '127.0.0.1';
+ $name = $this->getParamValue('dbname');
+ if (empty( $name )) {
+ die( "Database name must be set" );
+ }
+ $db[ 'dsn' ] = "mysql:host={$host};dbname={$name}";
+ if (empty( $username = $this->getParamValue('username') )) {
+ die( "Database username must be set" );
+ }
+ $db[ 'username' ] = $username;
+ if (empty( $password = $this->getParamValue('password') )) {
+ die( "Database password must be set" );
+ }
+ $db[ 'password' ] = $password;
+ }
+ $db[ 'dbtype' ] = $dbType;
+ $this->db = $db;
+ return $db;
+ }
+
+ /**
+ * Copy db connection file accroding to choosen driver
+ */
+ private function initDb()
+ {
+ if (!empty( $configPath = $this->environment[ 'setDbConnection' ] )) {
+ if (preg_match('/(.*)\/.*/', $configPath, $matches)) {
+ $path = $matches[ 1 ];
+ } else {
+ $this->printError("Unknown error while trying to init database");
+ exit( 1 );
+ }
+ $filename = "db{$this->db['dbtype']}.php";
+ $all = !empty( $this->getParamValue('overwrite') ) ? false : true;
+ $fullpath = "{$path}/{$filename}";
+ if ($this->copyFile("environments/{$filename}", $fullpath, $all)) {
+ $this->rewriteDb($fullpath, $configPath);
+ }
+ }
+ }
+
+ /**
+ * Rewrite params in db config and local config files
+ *
+ * @param string $path
+ * @param string $config
+ */
+ private function rewriteDb(string $path, string $config)
+ {
+ $db = $this->db;
+ $this->setParam('dsn', $db[ 'dsn' ], $path);
+ $this->setParam('username', $db[ 'username' ], $path);
+ $this->setParam('password', $db[ 'password' ], $path);
+ if ($this->db[ 'dbtype' ] == 'postgresql') {
+ $this->setParam('defaultSchema', $db[ 'schema' ], $path);
+ }
+ $filename = "db{$this->db['dbtype']}.php";
+ $this->setParam('db', "require('{$filename}')", $config, true, true);
+ $driver = ucfirst($db[ 'dbtype' ]);
+ echo $this->formatMessage(
+ "Database access file $path was created and filled with configurations for database driver {$driver}",
+ [ 'fg-green' ]
+ ) . "\n";
+ echo $this->formatMessage(
+ "Database access file $path was linked to local config file $config",
+ [ 'fg-green' ]
+ ) . "\n";
+ echo $this->formatMessage("Database Access: ", [ 'bg-yellow' ]) . $this->formatMessage(
+ $this->db[ 'dsn' ],
+ [
+ 'bg-yellow',
+ 'fg-blue',
+ ]
+ ) . $this->formatMessage(', username: ', [ 'bg-yellow' ]) . $this->formatMessage(
+ $this->db[ 'username' ],
+ [
+ 'bg-yellow',
+ 'fg-blue',
+ ]
+ ) . "\n";
+ echo " Database initialization completed\n";
+ echo " =================================\n";
+ }
+
+ /**
+ * Prints error message.
+ *
+ * @param string $message message
+ */
+ private function printError(string $message)
+ {
+ echo "\n " . $this->formatMessage(
+ "Error. $message",
+ [
+ 'fg-red',
+ 'bold',
+ ]
+ ) . " \n";
+ }
+
+ /**
+ * Returns true if the stream supports colorization. ANSI colors are disabled if not supported by the stream.
+ * - windows without ansicon
+ * - not tty consoles
+ *
+ * @return boolean true if the stream supports ANSI colors, otherwise false.
+ */
+ private function ansiColorsSupported(): bool
+ {
+ return DIRECTORY_SEPARATOR === '\\' ? getenv('ANSICON') !== false || getenv(
+ 'ConEmuANSI'
+ ) === 'ON' : function_exists('posix_isatty') && @posix_isatty(STDOUT);
+ }
+
+ /**
+ * Get ANSI code of style.
+ *
+ * @param string $name style name
+ *
+ * @return integer ANSI code of style.
+ */
+ private function getStyleCode(string $name): int
+ {
+ $styles = [
+ 'bold' => 1,
+ 'fg-black' => 30,
+ 'fg-red' => 31,
+ 'fg-green' => 32,
+ 'fg-yellow' => 33,
+ 'fg-blue' => 34,
+ 'fg-magenta' => 35,
+ 'fg-cyan' => 36,
+ 'fg-white' => 37,
+ 'bg-black' => 40,
+ 'bg-red' => 41,
+ 'bg-green' => 42,
+ 'bg-yellow' => 43,
+ 'bg-blue' => 44,
+ 'bg-magenta' => 45,
+ 'bg-cyan' => 46,
+ 'bg-white' => 47,
+ ];
+ return $styles[ $name ];
+ }
+
+ /**
+ * Formats message using styles if STDOUT supports it.
+ *
+ * @param string $message message
+ * @param string[] $styles styles
+ *
+ * @return string formatted message.
+ */
+ public function formatMessage(string $message, array $styles = []): string
+ {
+ if (empty( $styles ) || !$this->ansiColorsSupported()) {
+ return $message;
+ }
+
+ return sprintf("\x1b[%sm", implode(';', array_map('getStyleCode', $styles))) . $message . "\x1b[0m";
+ }
+
+ /**
+ * Inform that an application initialized without database. Exit code 0, means success.
+ */
+ private function noDatabaseMessage()
+ {
+ echo $this->formatMessage(
+ "\n Attention: ",
+ [
+ 'bold',
+ 'fg-red',
+ 'bg-yellow',
+ ]
+ );
+ echo $this->formatMessage(
+ "Application initialized without database. Set it manually in {$this->getRoot()}/common/config/main-local.php and run migration",
+ [
+ 'bold',
+ 'bg-yellow',
+ ]
+ ) . "\n";
+ exit( 0 );
+ }
+
+ /**
+ * Perform database migration if input param migrate doesn't set to 'no'
+ */
+ private function migrate()
+ {
+ $migrate = $this->getParamValue('migrate');
+ if ($migrate == 'no') {
+ echo $this->formatMessage(
+ "Migration skipped by user. In order to application work correct you will need to run it manually",
+ [
+ 'bg-yellow',
+ 'bold',
+ ]
+ ) . "\n";
+ exit( 0 );
+ } elseif ($migrate != 'yes') {
+ do {
+ echo " Do you want to perform database migration? [yes|no]";
+ $answer = trim(fgets(STDIN));
+ } while (strncasecmp($answer, 'y', 1) !== 0 && strncasecmp($answer, 'n', 1) !== 0);
+ if (strncasecmp($answer, 'n', 1) === 0) {
+ echo $this->formatMessage(
+ "Migration skipped by user. In order to application work correct you will need to run it manually",
+ [
+ 'bg-yellow',
+ 'bold',
+ ]
+ ) . "\n";
+ exit( 0 );
+ }
+ }
+ echo $this->formatMessage("Migration begins...", [ 'fg-yellow' ]) . "\n";
+ $migrationPath = $this->getParamValue('migrationPath');
+ if (empty( $migrationPath )) {
+ $migrationPath = 'vendor/artweb/artbox-core/migrations';
+ }
+ $result = exec("php yii migrate --migrationPath=$migrationPath --interactive=0", $output, $return);
+ if ($return !== 0) {
+ $this->printError("Migration cannot be applied. Run it manually to check the reason");
+ exit( 1 );
+ }
+ $this->writeLine($result);
+ foreach ($output as $value) {
+ $this->writeLine($value);
+ }
+ echo $this->formatMessage("Migration ended successfully", [ 'fg-yellow' ]) . "\n";
+ }
+
+ /**
+ * Write line of code followed by new line symbol
+ *
+ * @param string $string
+ */
+ private function writeLine(string $string)
+ {
+ echo $string . "\n";
+ }
+
+ /**
+ * Perform user creation if input param user doesn't set to 'no'
+ */
+ private function createUser()
+ {
+ $params = $this->getParams();
+ if (!isset( $params[ 'defaultuser' ] )) {
+ if ($this->getParamValue('user') == 'no') {
+ echo $this->formatMessage(
+ "User creation skipped by user. Run command 'php yii user/create' manually to create user.",
+ [
+ 'bg-yellow',
+ 'bold',
+ ]
+ ) . "\n";
+ exit( 0 );
+ }
+ do {
+ echo " Do you want to create user? [yes|no]";
+ $answer = trim(fgets(STDIN));
+ } while (strncasecmp($answer, 'y', 1) !== 0 && strncasecmp($answer, 'n', 1) !== 0);
+ if (strncasecmp($answer, 'n', 1) === 0) {
+ echo $this->formatMessage(
+ "User creation skipped by user. Run command 'php yii user/create' manually to create user.",
+ [
+ 'bg-yellow',
+ 'bold',
+ ]
+ ) . "\n";
+ exit( 0 );
+ }
+ echo "\n Enter username: ";
+ $username = trim(fgets(STDIN));
+ echo "\n Enter email: ";
+ $email = trim(fgets(STDIN));
+ echo "\n Enter password: ";
+ $password = trim(fgets(STDIN));
+ echo "\n";
+ $result = exec("php yii create/user $username $email $password", $output, $return);
+ } else {
+ $result = exec("php yii create/user", $output, $return);
+ }
+ $this->handleUserCreation($result, $output, $return);
+ }
+
+ /**
+ * Handle user creation result
+ *
+ * @param string $result
+ * @param array $output
+ * @param int $return
+ */
+ private function handleUserCreation($result, $output, $return)
+ {
+ if ($return !== 0) {
+ $this->printError("User cannot be created. Run 'php yii create/user' manually to check the reason");
+ exit( 1 );
+ }
+ $this->writeLine($result);
+ echo $this->formatMessage("User created successfully", [ 'fg-yellow' ]) . "\n";
+ }
+
+ /**
+ * Congratulate with successfull installation and optionally open browser
+ */
+ private function congratulate()
+ {
+ echo "\n" . $this->formatMessage(
+ "Congratulations. Artbox Basic has been successfully installed.",
+ [
+ 'fg-yellow',
+ 'bold',
+ ]
+ ) . "\n";
+ $url = $this->getParamValue('o');
+ if (!empty( $url )) {
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+ shell_exec("explorer '{$url}'");
+ } else {
+ shell_exec("sensible-browser {$url}");
+ }
+ }
+ }
+ }
+
\ No newline at end of file
diff --git a/common/config/.gitignore b/common/config/.gitignore
index 4104a6e..b2e5776 100644
--- a/common/config/.gitignore
+++ b/common/config/.gitignore
@@ -1,4 +1,5 @@
main-local.php
+db*
params-local.php
test-local.php
settings.php
\ No newline at end of file
diff --git a/console/controllers/CreateController.php b/console/controllers/CreateController.php
index 7315520..71d603b 100644
--- a/console/controllers/CreateController.php
+++ b/console/controllers/CreateController.php
@@ -12,18 +12,30 @@
*/
class CreateController extends Controller
{
- public function actionUser()
+ public function actionUser($username = null, $email = null, $password = null)
{
- $user = new User();
- $user->username = 'admin';
- $user->email = 'admin@example.com';
- $user->setPassword('admin321');
+ $username = $username ? : 'admin';
+ $user = User::find()
+ ->where([ 'username' => $username ])
+ ->one();
+ if (empty( $user )) {
+ $user = new User();
+ $user->username = $username;
+ }
+ $user->email = $email ? : 'admin@example.com';
+ $user->setPassword($password ? : 'admin321');
$user->generateAuthKey();
if ($user->save()) {
- $this->stdout('User created' . "\n", Console::FG_GREEN);
+ if ($user->isNewRecord) {
+ $this->stdout('User created' . "\n", Console::FG_GREEN);
+ } else {
+ $this->stdout('User updated' . "\n", Console::FG_GREEN);
+ }
} else {
$this->stdout('Error!' . "\n", Console::FG_RED);
+ return self::EXIT_CODE_ERROR;
}
+ return self::EXIT_CODE_NORMAL;
}
}
\ No newline at end of file
diff --git a/environments/dbmysql.php b/environments/dbmysql.php
new file mode 100644
index 0000000..dbf6d83
--- /dev/null
+++ b/environments/dbmysql.php
@@ -0,0 +1,9 @@
+ 'yii\db\Connection',
+ 'dsn' => '',
+ 'username' => '',
+ 'password' => '',
+ 'charset' => 'utf8',
+ ];
+ //mysql:host=localhost;dbname=yii2advanced
\ No newline at end of file
diff --git a/environments/dbpostgresql.php b/environments/dbpostgresql.php
new file mode 100644
index 0000000..ee580f4
--- /dev/null
+++ b/environments/dbpostgresql.php
@@ -0,0 +1,15 @@
+ 'yii\db\Connection',
+ 'dsn' => '',
+ 'username' => '',
+ 'password' => '',
+ 'charset' => 'utf8',
+ 'schemaMap' => [
+ 'pgsql' => [
+ 'class' => 'yii\db\pgsql\Schema',
+ 'defaultSchema' => '',
+ ],
+ ],
+ ];
+ //DSN: pgsql:host=127.0.0.1;port=5432;dbname=name
\ No newline at end of file
diff --git a/environments/dev/common/config/main-local.php b/environments/dev/common/config/main-local.php
index 43db30e..11c239d 100644
--- a/environments/dev/common/config/main-local.php
+++ b/environments/dev/common/config/main-local.php
@@ -1,13 +1,7 @@
[
- 'db' => [
- 'class' => 'yii\db\Connection',
- 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
- 'username' => 'root',
- 'password' => '',
- 'charset' => 'utf8',
- ],
+ 'db' => '',
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '@common/mail',
diff --git a/environments/index.php b/environments/index.php
index 5c3cca3..0070519 100644
--- a/environments/index.php
+++ b/environments/index.php
@@ -30,14 +30,14 @@
*/
return [
'Development' => [
- 'path' => 'dev',
- 'setWritable' => [
+ 'path' => 'dev',
+ 'setWritable' => [
'backend/runtime',
'backend/web/assets',
'frontend/runtime',
'frontend/web/assets',
],
- 'setExecutable' => [
+ 'setExecutable' => [
'yii',
'yii_test',
],
@@ -45,21 +45,23 @@ return [
'backend/config/main-local.php',
'frontend/config/main-local.php',
],
+ 'setDbConnection' => 'common/config/main-local.php',
],
'Production' => [
- 'path' => 'prod',
- 'setWritable' => [
+ 'path' => 'prod',
+ 'setWritable' => [
'backend/runtime',
'backend/web/assets',
'frontend/runtime',
'frontend/web/assets',
],
- 'setExecutable' => [
+ 'setExecutable' => [
'yii',
],
'setCookieValidationKey' => [
'backend/config/main-local.php',
'frontend/config/main-local.php',
],
+ 'setDbConnection' => 'common/config/main-local.php',
],
];
diff --git a/environments/prod/common/config/main-local.php b/environments/prod/common/config/main-local.php
index 84c4d9f..195993f 100644
--- a/environments/prod/common/config/main-local.php
+++ b/environments/prod/common/config/main-local.php
@@ -1,13 +1,7 @@
[
- 'db' => [
- 'class' => 'yii\db\Connection',
- 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
- 'username' => 'root',
- 'password' => '',
- 'charset' => 'utf8',
- ],
+ 'db' => '',
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '@common/mail',
diff --git a/init b/init
index 7aaf086..89eb341 100644
--- a/init
+++ b/init
@@ -1,299 +1,18 @@
#!/usr/bin/env php
- *
- * @link http://www.yiiframework.com/
- * @copyright Copyright (c) 2008 Yii Software LLC
- * @license http://www.yiiframework.com/license/
- */
-
-if (!extension_loaded('openssl')) {
- die('The OpenSSL PHP extension is required by Yii2.');
-}
-
-$params = getParams();
-$root = str_replace('\\', '/', __DIR__);
-$envs = require("$root/environments/index.php");
-$envNames = array_keys($envs);
-
-echo "Yii Application Initialization Tool v1.0\n\n";
-
-$envName = null;
-if (empty($params['env']) || $params['env'] === '1') {
- echo "Which environment do you want the application to be initialized in?\n\n";
- foreach ($envNames as $i => $name) {
- echo " [$i] $name\n";
- }
- echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
- $answer = trim(fgets(STDIN));
-
- if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) {
- echo "\n Quit initialization.\n";
- exit(0);
- }
-
- if (isset($envNames[$answer])) {
- $envName = $envNames[$answer];
- }
-} else {
- $envName = $params['env'];
-}
-
-if (!in_array($envName, $envNames)) {
- $envsList = implode(', ', $envNames);
- echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n";
- exit(2);
-}
-
-$env = $envs[$envName];
-
-if (empty($params['env'])) {
- echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
- $answer = trim(fgets(STDIN));
- if (strncasecmp($answer, 'y', 1)) {
- echo "\n Quit initialization.\n";
- exit(0);
- }
-}
-
-echo "\n Start initialization ...\n\n";
-$files = getFileList("$root/environments/{$env['path']}");
-if (isset($env['skipFiles'])) {
- $skipFiles = $env['skipFiles'];
- array_walk($skipFiles, function(&$value) use($env, $root) { $value = "$root/$value"; });
- $files = array_diff($files, array_intersect_key($env['skipFiles'], array_filter($skipFiles, 'file_exists')));
-}
-$all = false;
-foreach ($files as $file) {
- if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) {
- break;
- }
-}
-
-$callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable', 'createSymlink'];
-foreach ($callbacks as $callback) {
- if (!empty($env[$callback])) {
- $callback($root, $env[$callback]);
- }
-}
-
-echo "\n ... initialization completed.\n\n";
-
-function getFileList($root, $basePath = '')
-{
- $files = [];
- $handle = opendir($root);
- while (($path = readdir($handle)) !== false) {
- if ($path === '.git' || $path === '.svn' || $path === '.' || $path === '..') {
- continue;
- }
- $fullPath = "$root/$path";
- $relativePath = $basePath === '' ? $path : "$basePath/$path";
- if (is_dir($fullPath)) {
- $files = array_merge($files, getFileList($fullPath, $relativePath));
- } else {
- $files[] = $relativePath;
- }
- }
- closedir($handle);
- return $files;
-}
-
-function copyFile($root, $source, $target, &$all, $params)
-{
- if (!is_file($root . '/' . $source)) {
- echo " skip $target ($source not exist)\n";
- return true;
- }
- if (is_file($root . '/' . $target)) {
- if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
- echo " unchanged $target\n";
- return true;
- }
- if ($all) {
- echo " overwrite $target\n";
- } else {
- echo " exist $target\n";
- echo " ...overwrite? [Yes|No|All|Quit] ";
-
-
- $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN));
- if (!strncasecmp($answer, 'q', 1)) {
- return false;
- } else {
- if (!strncasecmp($answer, 'y', 1)) {
- echo " overwrite $target\n";
- } else {
- if (!strncasecmp($answer, 'a', 1)) {
- echo " overwrite $target\n";
- $all = true;
- } else {
- echo " skip $target\n";
- return true;
- }
- }
- }
- }
- file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
- return true;
- }
- echo " generate $target\n";
- @mkdir(dirname($root . '/' . $target), 0777, true);
- file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
- return true;
-}
-
-function getParams()
-{
- $rawParams = [];
- if (isset($_SERVER['argv'])) {
- $rawParams = $_SERVER['argv'];
- array_shift($rawParams);
- }
-
- $params = [];
- foreach ($rawParams as $param) {
- if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
- $name = $matches[1];
- $params[$name] = isset($matches[3]) ? $matches[3] : true;
- } else {
- $params[] = $param;
- }
- }
- return $params;
-}
-
-function setWritable($root, $paths)
-{
- foreach ($paths as $writable) {
- if (is_dir("$root/$writable")) {
- if (@chmod("$root/$writable", 0777)) {
- echo " chmod 0777 $writable\n";
- } else {
- printError("Operation chmod not permitted for directory $writable.");
- }
- } else {
- printError("Directory $writable does not exist.");
- }
- }
-}
-
-function setExecutable($root, $paths)
-{
- foreach ($paths as $executable) {
- if (file_exists("$root/$executable")) {
- if (@chmod("$root/$executable", 0755)) {
- echo " chmod 0755 $executable\n";
- } else {
- printError("Operation chmod not permitted for $executable.");
- }
- } else {
- printError("$executable does not exist.");
- }
- }
-}
-
-function setCookieValidationKey($root, $paths)
-{
- foreach ($paths as $file) {
- echo " generate cookie validation key in $file\n";
- $file = $root . '/' . $file;
- $length = 32;
- $bytes = openssl_random_pseudo_bytes($length);
- $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
- $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file));
- file_put_contents($file, $content);
- }
-}
-
-function createSymlink($root, $links)
-{
- foreach ($links as $link => $target) {
- //first removing folders to avoid errors if the folder already exists
- @rmdir($root . "/" . $link);
- //next removing existing symlink in order to update the target
- if (is_link($root . "/" . $link)) {
- @unlink($root . "/" . $link);
- }
- if (@symlink($root . "/" . $target, $root . "/" . $link)) {
- echo " symlink $root/$target $root/$link\n";
- } else {
- printError("Cannot create symlink $root/$target $root/$link.");
- }
- }
-}
-
-/**
- * Prints error message.
- * @param string $message message
- */
-function printError($message)
-{
- echo "\n " . formatMessage("Error. $message", ['fg-red']) . " \n";
-}
-
-/**
- * Returns true if the stream supports colorization. ANSI colors are disabled if not supported by the stream.
- *
- * - windows without ansicon
- * - not tty consoles
- *
- * @return boolean true if the stream supports ANSI colors, otherwise false.
- */
-function ansiColorsSupported()
-{
- return DIRECTORY_SEPARATOR === '\\'
- ? getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON'
- : function_exists('posix_isatty') && @posix_isatty(STDOUT);
-}
-
-/**
- * Get ANSI code of style.
- * @param string $name style name
- * @return integer ANSI code of style.
- */
-function getStyleCode($name)
-{
- $styles = [
- 'bold' => 1,
- 'fg-black' => 30,
- 'fg-red' => 31,
- 'fg-green' => 32,
- 'fg-yellow' => 33,
- 'fg-blue' => 34,
- 'fg-magenta' => 35,
- 'fg-cyan' => 36,
- 'fg-white' => 37,
- 'bg-black' => 40,
- 'bg-red' => 41,
- 'bg-green' => 42,
- 'bg-yellow' => 43,
- 'bg-blue' => 44,
- 'bg-magenta' => 45,
- 'bg-cyan' => 46,
- 'bg-white' => 47,
- ];
- return $styles[$name];
-}
-
-/**
- * Formats message using styles if STDOUT supports it.
- * @param string $message message
- * @param string[] $styles styles
- * @return string formatted message.
- */
-function formatMessage($message, $styles)
-{
- if (empty($styles) || !ansiColorsSupported()) {
- return $message;
- }
-
- return sprintf("\x1b[%sm", implode(';', array_map('getStyleCode', $styles))) . $message . "\x1b[0m";
-}
+ /**
+ * Yii Application Initialization Tool
+ * In order to run in non-interactive mode:
+ * init --env=Development --overwrite=n
+ *
+ * @author Alexander Makarov
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+ require( 'Initializer.php' );
+ if (!extension_loaded('openssl')) {
+ die( 'The OpenSSL PHP extension is required by Yii2.' );
+ }
+
+ Initializer::initialize();
--
libgit2 0.21.4