Commit 2c498f6044df41a5cb106abfd07c24e60cf6c2f7

Authored by Yarik
1 parent 2f3cd090

Initializer completed

.gitignore
... ... @@ -34,4 +34,4 @@ phpunit.phar
34 34 # vagrant runtime
35 35 /.vagrant
36 36 /artweb/
37 37 -/storage
  38 +/storage
38 39 \ No newline at end of file
... ...
Initializer.php 0 → 100644
  1 +<?php
  2 +
  3 + /**
  4 + * Class Initializer
  5 + *
  6 + * Class to initialize Artbox application
  7 + */
  8 + class Initializer
  9 + {
  10 + private $params = [];
  11 + private $root;
  12 + private $envs = [];
  13 + private $environment;
  14 + private $db = [];
  15 + private static $instance;
  16 +
  17 + const VERSION = '1.0';
  18 + const CALLBACKS = [
  19 + 'setCookieValidationKey',
  20 + 'setWritable',
  21 + 'setExecutable',
  22 + 'createSymlink',
  23 + ];
  24 +
  25 + /**
  26 + * Initialize application
  27 + */
  28 + public static function initialize()
  29 + {
  30 + $instance = self::getInstance();
  31 + $instance->defineEnvironment();
  32 + $instance->startInitialization();
  33 + if ($instance->askInitDb()) {
  34 + $instance->defineDb();
  35 + $instance->migrate();
  36 + $instance->createUser();
  37 + $instance->congratulate();
  38 + }
  39 + }
  40 +
  41 + /**
  42 + * Get instance of Initializer
  43 + *
  44 + * @return mixed
  45 + */
  46 + public static function getInstance(): Initializer
  47 + {
  48 + if (empty( self::$instance )) {
  49 + self::$instance = new self();
  50 + }
  51 + return self::$instance;
  52 + }
  53 +
  54 + /**
  55 + * Initializer private constructor. You can get Singleton with getInstance()
  56 + *
  57 + * Availiable options:
  58 + * * --env - One of available environments
  59 + * * --overwrite - Do overwrite all files without confirmation
  60 + * * --dbinit - Initialize database after app initialization
  61 + * * --dbtype - Database type. Available: postgresql, mysql
  62 + * * --host - Database host, default to 127.0.0.1
  63 + * * --port - Database port used by postgresql, default to 5432
  64 + * * --schema - Database schema for postresql, default to public
  65 + * * --dbname - Database name, required
  66 + * * --username - Database username, required
  67 + * * --password - Database password, required
  68 + * * --migrationPath - Migration path, default to vendor/artweb/artbox-core/migrations
  69 + * * --migrate - Whether to migrate, default to apply, set no to skip migration
  70 + * * --user_username - Username for user creation
  71 + * * --user_email - Email for user creation
  72 + * * --user_password - Password for user creation
  73 + * * --user - Whether to create user, default to yes, set no to skip creation
  74 + * * --defaultuser - Whether to use default user creation
  75 + * * --o - Webpage to open after intallaction process
  76 + *
  77 + * @see Initializer::getInstance()
  78 + */
  79 + private function __construct()
  80 + {
  81 + echo $this->formatMessage(
  82 + "\tArtbox Application Initialization Tool v" . self::VERSION,
  83 + [ 'bold' ]
  84 + ) . "\n\n";
  85 + }
  86 +
  87 + /**
  88 + * Define environment for an application
  89 + *
  90 + * @return string
  91 + */
  92 + private function defineEnvironment()
  93 + {
  94 + $envName = $this->getParamValue('env');
  95 + $envs = $this->getEnvironmentNames();
  96 + if (empty( $envName ) || $envName === '1') {
  97 + do {
  98 + $envName = $this->askEnvironment($envs);
  99 + echo "\n Initialize the application under '{$envName}' environment? [yes|no] ";
  100 + $answer = trim(fgets(STDIN));
  101 + } while (strncasecmp($answer, 'y', 1));
  102 + } else {
  103 + if (!in_array($envName, $envs)) {
  104 + $this->printError("Wrong environment name, available list: " . implode(', ', $envs));
  105 + exit( 1 );
  106 + }
  107 + }
  108 + $this->environment = $this->envs[ $envName ];
  109 + return $this->environment;
  110 + }
  111 +
  112 + /**
  113 + * Start actual application initialization with files overwriting
  114 + */
  115 + private function startInitialization()
  116 + {
  117 + echo "\n Start initialization\n";
  118 + echo " =====================\n";
  119 +
  120 + $this->rewriteFiles();
  121 + $this->callback();
  122 + echo "\n App initialization completed\n";
  123 + echo " ==============================\n";
  124 + }
  125 +
  126 + /**
  127 + * Ask whether to init databse. If dbinit param is set, this step will be skipped.
  128 + *
  129 + * @return bool
  130 + */
  131 + private function askInitDb(): bool
  132 + {
  133 + echo " Start database initialization\n";
  134 + $params = $this->getParams();
  135 + if (!isset( $params[ 'dbinit' ] )) {
  136 + do {
  137 + echo $this->formatMessage("\n Init the database? [yes|no] ", [ 'bold' ]);
  138 + $answer = trim(fgets(STDIN));
  139 + } while (( strncasecmp($answer, 'y', 1) !== 0 ) && ( strncasecmp($answer, 'n', 1) !== 0 ));
  140 + if (strncasecmp($answer, 'n', 1) == 0) {
  141 + $this->noDatabaseMessage();
  142 + }
  143 + }
  144 + return true;
  145 + }
  146 +
  147 + /**
  148 + * Define which database driver to use. Available options: postgresql, mysql
  149 + */
  150 + private function defineDb()
  151 + {
  152 + $params = $this->getParams();
  153 + if (isset( $params[ 'dbinit' ] )) {
  154 + $this->validateConnection();
  155 + } else {
  156 + $answer = '';
  157 + do {
  158 + if (!empty( $answer )) {
  159 + $this->printError("Incorrect database type. Try again or write 'quit' to exit");
  160 + }
  161 + echo "\n Which database do you want to use? [postgresql|mysql] ";
  162 + $answer = trim(fgets(STDIN));
  163 +
  164 + } while (( strncasecmp($answer, 'q', 1) !== 0 ) && ( !in_array(
  165 + $answer,
  166 + [
  167 + 'postgresql',
  168 + 'mysql',
  169 + 'p',
  170 + 'm',
  171 + ]
  172 + ) ));
  173 + if (strncasecmp($answer, 'q', 1) === 0) {
  174 + $this->noDatabaseMessage();
  175 + }
  176 + if (strncasecmp($answer, 'p', 1) === 0) {
  177 + $answer = 'postgresql';
  178 + } else {
  179 + $answer = 'mysql';
  180 + }
  181 + if ($answer == 'postgresql') {
  182 + $this->initPostgres();
  183 + } else {
  184 + $this->initMysql();
  185 + }
  186 + }
  187 + $this->initDb();
  188 + }
  189 +
  190 + /**
  191 + * Get parsed params
  192 + *
  193 + * @see Initializer::parseParams()
  194 + *
  195 + * @return array
  196 + */
  197 + private function getParams(): array
  198 + {
  199 + if (empty( $this->params )) {
  200 + $this->parseParams();
  201 + }
  202 + return $this->params;
  203 + }
  204 +
  205 + /**
  206 + * Get params from input string
  207 + * For example
  208 + *
  209 + * **<code>php init test --param1=value1 --param2=value2</code>**
  210 + *
  211 + * will get
  212 + *
  213 + * <code>**
  214 + * [
  215 + * test,
  216 + * value1,
  217 + * value2
  218 + * ]
  219 + * </code>
  220 + *
  221 + * @return array
  222 + */
  223 + private function parseParams(): array
  224 + {
  225 + $rawParams = [];
  226 + if (isset( $_SERVER[ 'argv' ] )) {
  227 + $rawParams = $_SERVER[ 'argv' ];
  228 + array_shift($rawParams);
  229 + }
  230 +
  231 + $params = [];
  232 + foreach ($rawParams as $param) {
  233 + if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
  234 + $name = $matches[ 1 ];
  235 + $params[ $name ] = isset( $matches[ 3 ] ) ? $matches[ 3 ] : true;
  236 + } else {
  237 + $params[] = $param;
  238 + }
  239 + }
  240 + $this->params = $params;
  241 + return $this->params;
  242 + }
  243 +
  244 + /**
  245 + * Get value of input param. Empty string if not exist.
  246 + *
  247 + * @param string $name
  248 + *
  249 + * @return string
  250 + */
  251 + private function getParamValue(string $name): string
  252 + {
  253 + $params = $this->getParams();
  254 + if (isset( $params[ $name ] ) && !empty( $params[ $name ] )) {
  255 + return $params[ $name ];
  256 + } else {
  257 + return '';
  258 + }
  259 + }
  260 +
  261 + /**
  262 + * Get project root directory according to file system
  263 + *
  264 + * @return mixed
  265 + */
  266 + private function getRoot(): string
  267 + {
  268 + if (empty( $this->root )) {
  269 + $this->root = str_replace('\\', '/', __DIR__);
  270 + }
  271 + return $this->root;
  272 + }
  273 +
  274 + /**
  275 + * Get available environments from environments/index.php file
  276 + *
  277 + * Follow environments/index.php manifest to create your own environments
  278 + *
  279 + * @return array
  280 + */
  281 + private function getEnvironments(): array
  282 + {
  283 + $path = "{$this->getRoot()}/environments/index.php";
  284 + if (empty( $this->envs )) {
  285 + /** @noinspection PhpIncludeInspection */
  286 + $this->envs = require( $path );
  287 + }
  288 + if (empty( $this->envs )) {
  289 + die( "There are no available environments in $path" );
  290 + }
  291 + return $this->envs;
  292 + }
  293 +
  294 + /**
  295 + * Get environment names
  296 + *
  297 + * @return array
  298 + */
  299 + private function getEnvironmentNames(): array
  300 + {
  301 + return array_keys($this->getEnvironments());
  302 + }
  303 +
  304 + /**
  305 + * Show user variants to choose environment from
  306 + *
  307 + * @param array $envs
  308 + *
  309 + * @return string
  310 + */
  311 + private function askEnvironment(array $envs): string
  312 + {
  313 + echo "Which environment do you want the application to be initialized in?\n\n";
  314 + foreach ($envs as $i => $name) {
  315 + echo " [$i] $name\n";
  316 + }
  317 + $answer = $this->offerEnvironment(count($envs));
  318 + while (!( ( ctype_digit($answer) && in_array($answer, range(0, count($envs) - 1)) ) || $answer === 'q' )) {
  319 + $answer = $this->offerEnvironment(count($envs));
  320 + }
  321 + if ($answer === 'q') {
  322 + echo "\n Quit initialization.\n";
  323 + exit( 0 );
  324 + } else {
  325 + if (isset( $envs[ $answer ] )) {
  326 + $envName = $envs[ $answer ];
  327 + } else {
  328 + die( "Error while trying to get environment name. Try another one." );
  329 + }
  330 + }
  331 + return $envName;
  332 + }
  333 +
  334 + /**
  335 + * Offer user to choose environment number
  336 + *
  337 + * @param int $count
  338 + *
  339 + * @return string
  340 + */
  341 + private function offerEnvironment(int $count): string
  342 + {
  343 + echo "\n Your choice [0-" . ( $count - 1 ) . ', or "q" to quit] ';
  344 + return trim(fgets(STDIN));
  345 + }
  346 +
  347 + /**
  348 + * Rewrite files by files in <code>environments/$environment['path']</code>
  349 + */
  350 + private function rewriteFiles()
  351 + {
  352 + $environment = $this->environment;
  353 + $root = $this->getRoot();
  354 + if (isset( $environment[ 'path' ] ) && !empty( $environment[ 'path' ] )) {
  355 + $path = $environment[ 'path' ];
  356 + } else {
  357 + $this->printError('Environment configuration failed. Please set path value.');
  358 + exit( 1 );
  359 + }
  360 + $files = $this->getFileList("$root/environments/$path");
  361 + if (isset( $environment[ 'skipFiles' ] )) {
  362 + $skipFiles = $environment[ 'skipFiles' ];
  363 + array_walk(
  364 + $skipFiles,
  365 + function (&$value) use ($root) {
  366 + $value = "$root/$value";
  367 + }
  368 + );
  369 + $files = array_diff(
  370 + $files,
  371 + array_intersect_key(
  372 + $environment[ 'skipFiles' ],
  373 + array_filter($skipFiles, 'file_exists')
  374 + )
  375 + );
  376 + }
  377 + $all = false;
  378 + foreach ($files as $file) {
  379 + if (!$this->copyFile("environments/{$path}/$file", $file, $all)) {
  380 + break;
  381 + }
  382 + }
  383 + }
  384 +
  385 + /**
  386 + * Recursively get all files from $root directory.
  387 + *
  388 + * This will ignore .git, .svn directories.
  389 + *
  390 + * @param string $root
  391 + * @param string $basePath
  392 + *
  393 + * @return array
  394 + */
  395 + private function getFileList(string $root, string $basePath = ''): array
  396 + {
  397 + $files = [];
  398 + $handle = opendir($root);
  399 + while (( $path = readdir($handle) ) !== false) {
  400 + if ($path === '.git' || $path === '.svn' || $path === '.' || $path === '..') {
  401 + continue;
  402 + }
  403 + $fullPath = "$root/$path";
  404 + $relativePath = $basePath === '' ? $path : "$basePath/$path";
  405 + if (is_dir($fullPath)) {
  406 + $files = array_merge($files, $this->getFileList($fullPath, $relativePath));
  407 + } else {
  408 + $files[] = $relativePath;
  409 + }
  410 + }
  411 + closedir($handle);
  412 + return $files;
  413 + }
  414 +
  415 + /**
  416 + * Run callbacks for application initialization
  417 + */
  418 + private function callback()
  419 + {
  420 + $environment = $this->environment;
  421 + foreach (self::CALLBACKS as $callback) {
  422 + if (!empty( $environment[ $callback ] )) {
  423 + $this->$callback($environment[ $callback ]);
  424 + }
  425 + }
  426 + }
  427 +
  428 + /**
  429 + * Set directories in $environment['setWrotable'] to chmod 0777
  430 + *
  431 + * @param $paths
  432 + */
  433 + private function setWritable(array $paths)
  434 + {
  435 + $root = $this->getRoot();
  436 + foreach ($paths as $writable) {
  437 + $fullPath = "$root/$writable";
  438 + if (is_dir($fullPath)) {
  439 + if (@chmod($fullPath, 0777)) {
  440 + echo $this->formatMessage(
  441 + " ***** Set writable $writable (chmod 0777)",
  442 + [ 'fg-yellow' ]
  443 + ) . "\n";
  444 + } else {
  445 + $this->printError("Operation chmod not permitted for directory $writable.");
  446 + }
  447 + } else {
  448 + if (!@mkdir($fullPath, 0777, true)) {
  449 + $this->printError("Directory $writable does not exist and cannot be created.");
  450 + }
  451 + }
  452 + }
  453 + }
  454 +
  455 + /**
  456 + * Set files in $environment['setExecutable'] to chmod 0755
  457 + *
  458 + * @param $paths
  459 + */
  460 + private function setExecutable(array $paths)
  461 + {
  462 + $root = $this->getRoot();
  463 + foreach ($paths as $executable) {
  464 + $fullPath = "$root/$executable";
  465 + if (file_exists($fullPath)) {
  466 + if (@chmod($fullPath, 0755)) {
  467 + echo $this->formatMessage(" ***** Set executable $executable (chmod 0755)") . "\n";
  468 + } else {
  469 + $this->printError("Operation chmod not permitted for $executable.");
  470 + }
  471 + } else {
  472 + $this->printError("$executable does not exist.");
  473 + }
  474 + }
  475 + }
  476 +
  477 + /**
  478 + * Set cookie validation keys to files in $environment['setCookieValidationKey'].
  479 + *
  480 + * @param $paths
  481 + */
  482 + private function setCookieValidationKey(array $paths)
  483 + {
  484 + $root = $this->getRoot();
  485 + foreach ($paths as $file) {
  486 + echo $this->formatMessage(
  487 + " ***** Generate cookie validation key in $file",
  488 + [
  489 + 'bold',
  490 + 'fg-magenta',
  491 + ]
  492 + ) . "\n";
  493 + $file = $root . '/' . $file;
  494 + $length = 32;
  495 + $bytes = openssl_random_pseudo_bytes($length);
  496 + $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
  497 + $this->setParam('cookieValidationKey', $key, $file);
  498 + }
  499 + }
  500 +
  501 + private function createSymlink(array $links)
  502 + {
  503 + $root = $this->getRoot();
  504 + foreach ($links as $link => $target) {
  505 + //first removing folders to avoid errors if the folder already exists
  506 + @rmdir($root . "/" . $link);
  507 + //next removing existing symlink in order to update the target
  508 + if (is_link($root . "/" . $link)) {
  509 + @unlink($root . "/" . $link);
  510 + }
  511 + if (@symlink($root . "/" . $target, $root . "/" . $link)) {
  512 + echo $this->formatMessage(" ***** Symlink $root/$target $root/$link", [ 'fg-blue' ]) . "\n";
  513 + } else {
  514 + $this->printError("Cannot create symlink $root/$target $root/$link.");
  515 + }
  516 + }
  517 + }
  518 +
  519 + /**
  520 + * Copy file from environment directory to project directory
  521 + *
  522 + * @param string $source Environment source file path
  523 + * @param string $target Project file path target
  524 + * @param bool $all Rewrite all flag
  525 + *
  526 + * @return bool
  527 + */
  528 + private function copyFile(string $source, string $target, bool &$all)
  529 + {
  530 + $root = $this->getRoot();
  531 + $params = $this->getParams();
  532 + if (!is_file($root . '/' . $source)) {
  533 + echo $this->formatMessage(" ----- skip $target ($source not exist)", [ 'fg-cyan' ]) . "\n";
  534 + return true;
  535 + }
  536 + if (is_file($root . '/' . $target)) {
  537 + if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
  538 + echo $this->formatMessage(" ----- unchanged $target", [ 'fg-cyan' ]) . "\n";
  539 + return true;
  540 + }
  541 + if ($all) {
  542 + echo $this->formatMessage(" ----- overwrite $target", [ 'fg-blue' ]) . "\n";
  543 + } else {
  544 + echo $this->formatMessage(" -- exist $target", [ 'fg-magenta' ]) . "\n";
  545 + echo " overwrite? [Yes|No|All|Quit] ";
  546 +
  547 + $answer = !empty( $params[ 'overwrite' ] ) ? $params[ 'overwrite' ] : trim(fgets(STDIN));
  548 + echo "\n";
  549 + if (!strncasecmp($answer, 'q', 1)) {
  550 + return false;
  551 + } else {
  552 + if (!strncasecmp($answer, 'y', 1)) {
  553 + echo $this->formatMessage(" ----- overwrite $target", [ 'fg-blue' ]) . "\n";
  554 + } else {
  555 + if (!strncasecmp($answer, 'a', 1)) {
  556 + echo $this->formatMessage(" ----- overwrite $target", [ 'fg-blue' ]) . "\n";
  557 + $all = true;
  558 + } else {
  559 + echo $this->formatMessage(
  560 + " ----- skip $target ($source not exist)",
  561 + [ 'fg-cyan' ]
  562 + ) . "\n";
  563 + return true;
  564 + }
  565 + }
  566 + }
  567 + }
  568 + file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
  569 + return true;
  570 + }
  571 + echo "\n" . $this->formatMessage(" ----- generate $target", [ 'fg-green' ]) . "\n";
  572 + @mkdir(dirname($root . '/' . $target), 0777, true);
  573 + file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
  574 + return true;
  575 + }
  576 +
  577 + /**
  578 + * Set param in file to particular value.
  579 + *
  580 + * For example: setParam('param', 'value', 'config.php') will replace content in config.php
  581 + *
  582 + * from
  583 + *
  584 + * 'param' => ''
  585 + *
  586 + * to
  587 + *
  588 + * 'param' => 'value'
  589 + *
  590 + * @param string $param
  591 + * @param string $value
  592 + * @param string $file
  593 + * @param bool $noQuote
  594 + * @param bool $force
  595 + * @param bool $alternate
  596 + */
  597 + private function setParam(
  598 + string $param,
  599 + string $value,
  600 + string $file,
  601 + bool $noQuote = false,
  602 + bool $force = false,
  603 + bool $alternate = false
  604 + ) {
  605 + if ($alternate) {
  606 + $regexp = '/(("|\')db("|\')\s*=>\s*)(.*|.*)/';
  607 + } else {
  608 + if ($force) {
  609 + $regexp = '/(("|\')' . $param . '("|\')\s*=>\s*)(".*"|\'.*\')/';
  610 + } else {
  611 + $regexp = '/(("|\')' . $param . '("|\')\s*=>\s*)(""|\'\')/';
  612 + }
  613 + }
  614 + if ($noQuote) {
  615 + $content = preg_replace(
  616 + $regexp,
  617 + "\\1$value",
  618 + file_get_contents($file)
  619 + );
  620 + } else {
  621 + $content = preg_replace(
  622 + $regexp,
  623 + "\\1'$value'",
  624 + file_get_contents($file)
  625 + );
  626 + }
  627 + file_put_contents($file, $content);
  628 + }
  629 +
  630 + /**
  631 + * Init postgres connection
  632 + *
  633 + * @return array
  634 + */
  635 + private function initPostgres(): array
  636 + {
  637 + $db = [
  638 + 'dbtype' => 'postgresql',
  639 + ];
  640 + echo "\n Enter your database host: ";
  641 + $host = trim(fgets(STDIN));
  642 + echo "\n Enter your database port: ";
  643 + $port = trim(fgets(STDIN));
  644 + echo "\n Enter your database schema: ";
  645 + $db[ 'schema' ] = trim(fgets(STDIN));
  646 + echo "\n Enter your database name: ";
  647 + $name = trim(fgets(STDIN));
  648 + echo "\n Enter your database username: ";
  649 + $db[ 'username' ] = trim(fgets(STDIN));
  650 + echo "\n Enter your database password: ";
  651 + $db[ 'password' ] = trim(fgets(STDIN));
  652 + $db[ 'dsn' ] = "pgsql:host={$host};port={$port};dbname={$name}";
  653 + $this->db = $db;
  654 + return $db;
  655 + }
  656 +
  657 + /**
  658 + * Init mysql connection
  659 + *
  660 + * @return array
  661 + */
  662 + private function initMysql(): array
  663 + {
  664 + $db = [
  665 + 'dbtype' => 'mysql',
  666 + ];
  667 + echo "\n Enter your database host: ";
  668 + $host = trim(fgets(STDIN));
  669 + echo "\n Enter your database name: ";
  670 + $name = trim(fgets(STDIN));
  671 + echo "\n Enter your database username: ";
  672 + $db[ 'username' ] = trim(fgets(STDIN));
  673 + echo "\n Enter your database password: ";
  674 + $db[ 'password' ] = trim(fgets(STDIN));
  675 + $db[ 'dsn' ] = "mysql:host={$host};dbname={$name}";
  676 + $this->db = $db;
  677 + return $db;
  678 + }
  679 +
  680 + /**
  681 + * Validate non-interactive db data and fill it for further actions.
  682 + *
  683 + * @return array
  684 + */
  685 + private function validateConnection(): array
  686 + {
  687 + $db = [];
  688 + $dbType = strtolower($this->getParamValue('dbtype'));
  689 + if ($dbType !== 'postgresql' && $dbType !== 'mysql') {
  690 + die( "Supported DB types are postgresql and mysql" );
  691 + }
  692 + if ($dbType === 'postgresql') {
  693 + $host = $this->getParamValue('host') ? : '127.0.0.1';
  694 + $port = $this->getParamValue('port') ? : '5432';
  695 + $db[ 'schema' ] = $this->getParamValue('schema') ? : 'public';
  696 + $name = $this->getParamValue('dbname');
  697 + if (empty( $name )) {
  698 + die( "Database name must be set" );
  699 + }
  700 + $db[ 'dsn' ] = "pgsql:host={$host};port={$port};dbname={$name}";
  701 + if (empty( $username = $this->getParamValue('username') )) {
  702 + die( "Database username must be set" );
  703 + }
  704 + $db[ 'username' ] = $username;
  705 + if (empty( $password = $this->getParamValue('password') )) {
  706 + die( "Database password must be set" );
  707 + }
  708 + $db[ 'password' ] = $password;
  709 + } else {
  710 + $host = $this->getParamValue('host') ? : '127.0.0.1';
  711 + $name = $this->getParamValue('dbname');
  712 + if (empty( $name )) {
  713 + die( "Database name must be set" );
  714 + }
  715 + $db[ 'dsn' ] = "mysql:host={$host};dbname={$name}";
  716 + if (empty( $username = $this->getParamValue('username') )) {
  717 + die( "Database username must be set" );
  718 + }
  719 + $db[ 'username' ] = $username;
  720 + if (empty( $password = $this->getParamValue('password') )) {
  721 + die( "Database password must be set" );
  722 + }
  723 + $db[ 'password' ] = $password;
  724 + }
  725 + $db[ 'dbtype' ] = $dbType;
  726 + $this->db = $db;
  727 + return $db;
  728 + }
  729 +
  730 + /**
  731 + * Copy db connection file accroding to choosen driver
  732 + */
  733 + private function initDb()
  734 + {
  735 + if (!empty( $configPath = $this->environment[ 'setDbConnection' ] )) {
  736 + if (preg_match('/(.*)\/.*/', $configPath, $matches)) {
  737 + $path = $matches[ 1 ];
  738 + } else {
  739 + $this->printError("Unknown error while trying to init database");
  740 + exit( 1 );
  741 + }
  742 + $filename = "db{$this->db['dbtype']}.php";
  743 + $all = !empty( $this->getParamValue('overwrite') ) ? false : true;
  744 + $fullpath = "{$path}/{$filename}";
  745 + if ($this->copyFile("environments/{$filename}", $fullpath, $all)) {
  746 + $this->rewriteDb($fullpath, $configPath);
  747 + }
  748 + }
  749 + }
  750 +
  751 + /**
  752 + * Rewrite params in db config and local config files
  753 + *
  754 + * @param string $path
  755 + * @param string $config
  756 + */
  757 + private function rewriteDb(string $path, string $config)
  758 + {
  759 + $db = $this->db;
  760 + $this->setParam('dsn', $db[ 'dsn' ], $path);
  761 + $this->setParam('username', $db[ 'username' ], $path);
  762 + $this->setParam('password', $db[ 'password' ], $path);
  763 + if ($this->db[ 'dbtype' ] == 'postgresql') {
  764 + $this->setParam('defaultSchema', $db[ 'schema' ], $path);
  765 + }
  766 + $filename = "db{$this->db['dbtype']}.php";
  767 + $this->setParam('db', "require('{$filename}')", $config, true, true);
  768 + $driver = ucfirst($db[ 'dbtype' ]);
  769 + echo $this->formatMessage(
  770 + "Database access file $path was created and filled with configurations for database driver {$driver}",
  771 + [ 'fg-green' ]
  772 + ) . "\n";
  773 + echo $this->formatMessage(
  774 + "Database access file $path was linked to local config file $config",
  775 + [ 'fg-green' ]
  776 + ) . "\n";
  777 + echo $this->formatMessage("Database Access: ", [ 'bg-yellow' ]) . $this->formatMessage(
  778 + $this->db[ 'dsn' ],
  779 + [
  780 + 'bg-yellow',
  781 + 'fg-blue',
  782 + ]
  783 + ) . $this->formatMessage(', username: ', [ 'bg-yellow' ]) . $this->formatMessage(
  784 + $this->db[ 'username' ],
  785 + [
  786 + 'bg-yellow',
  787 + 'fg-blue',
  788 + ]
  789 + ) . "\n";
  790 + echo " Database initialization completed\n";
  791 + echo " =================================\n";
  792 + }
  793 +
  794 + /**
  795 + * Prints error message.
  796 + *
  797 + * @param string $message message
  798 + */
  799 + private function printError(string $message)
  800 + {
  801 + echo "\n " . $this->formatMessage(
  802 + "Error. $message",
  803 + [
  804 + 'fg-red',
  805 + 'bold',
  806 + ]
  807 + ) . " \n";
  808 + }
  809 +
  810 + /**
  811 + * Returns true if the stream supports colorization. ANSI colors are disabled if not supported by the stream.
  812 + * - windows without ansicon
  813 + * - not tty consoles
  814 + *
  815 + * @return boolean true if the stream supports ANSI colors, otherwise false.
  816 + */
  817 + private function ansiColorsSupported(): bool
  818 + {
  819 + return DIRECTORY_SEPARATOR === '\\' ? getenv('ANSICON') !== false || getenv(
  820 + 'ConEmuANSI'
  821 + ) === 'ON' : function_exists('posix_isatty') && @posix_isatty(STDOUT);
  822 + }
  823 +
  824 + /**
  825 + * Get ANSI code of style.
  826 + *
  827 + * @param string $name style name
  828 + *
  829 + * @return integer ANSI code of style.
  830 + */
  831 + private function getStyleCode(string $name): int
  832 + {
  833 + $styles = [
  834 + 'bold' => 1,
  835 + 'fg-black' => 30,
  836 + 'fg-red' => 31,
  837 + 'fg-green' => 32,
  838 + 'fg-yellow' => 33,
  839 + 'fg-blue' => 34,
  840 + 'fg-magenta' => 35,
  841 + 'fg-cyan' => 36,
  842 + 'fg-white' => 37,
  843 + 'bg-black' => 40,
  844 + 'bg-red' => 41,
  845 + 'bg-green' => 42,
  846 + 'bg-yellow' => 43,
  847 + 'bg-blue' => 44,
  848 + 'bg-magenta' => 45,
  849 + 'bg-cyan' => 46,
  850 + 'bg-white' => 47,
  851 + ];
  852 + return $styles[ $name ];
  853 + }
  854 +
  855 + /**
  856 + * Formats message using styles if STDOUT supports it.
  857 + *
  858 + * @param string $message message
  859 + * @param string[] $styles styles
  860 + *
  861 + * @return string formatted message.
  862 + */
  863 + public function formatMessage(string $message, array $styles = []): string
  864 + {
  865 + if (empty( $styles ) || !$this->ansiColorsSupported()) {
  866 + return $message;
  867 + }
  868 +
  869 + return sprintf("\x1b[%sm", implode(';', array_map('getStyleCode', $styles))) . $message . "\x1b[0m";
  870 + }
  871 +
  872 + /**
  873 + * Inform that an application initialized without database. Exit code 0, means success.
  874 + */
  875 + private function noDatabaseMessage()
  876 + {
  877 + echo $this->formatMessage(
  878 + "\n Attention: ",
  879 + [
  880 + 'bold',
  881 + 'fg-red',
  882 + 'bg-yellow',
  883 + ]
  884 + );
  885 + echo $this->formatMessage(
  886 + "Application initialized without database. Set it manually in {$this->getRoot()}/common/config/main-local.php and run migration",
  887 + [
  888 + 'bold',
  889 + 'bg-yellow',
  890 + ]
  891 + ) . "\n";
  892 + exit( 0 );
  893 + }
  894 +
  895 + /**
  896 + * Perform database migration if input param migrate doesn't set to 'no'
  897 + */
  898 + private function migrate()
  899 + {
  900 + $migrate = $this->getParamValue('migrate');
  901 + if ($migrate == 'no') {
  902 + echo $this->formatMessage(
  903 + "Migration skipped by user. In order to application work correct you will need to run it manually",
  904 + [
  905 + 'bg-yellow',
  906 + 'bold',
  907 + ]
  908 + ) . "\n";
  909 + exit( 0 );
  910 + } elseif ($migrate != 'yes') {
  911 + do {
  912 + echo " Do you want to perform database migration? [yes|no]";
  913 + $answer = trim(fgets(STDIN));
  914 + } while (strncasecmp($answer, 'y', 1) !== 0 && strncasecmp($answer, 'n', 1) !== 0);
  915 + if (strncasecmp($answer, 'n', 1) === 0) {
  916 + echo $this->formatMessage(
  917 + "Migration skipped by user. In order to application work correct you will need to run it manually",
  918 + [
  919 + 'bg-yellow',
  920 + 'bold',
  921 + ]
  922 + ) . "\n";
  923 + exit( 0 );
  924 + }
  925 + }
  926 + echo $this->formatMessage("Migration begins...", [ 'fg-yellow' ]) . "\n";
  927 + $migrationPath = $this->getParamValue('migrationPath');
  928 + if (empty( $migrationPath )) {
  929 + $migrationPath = 'vendor/artweb/artbox-core/migrations';
  930 + }
  931 + $result = exec("php yii migrate --migrationPath=$migrationPath --interactive=0", $output, $return);
  932 + if ($return !== 0) {
  933 + $this->printError("Migration cannot be applied. Run it manually to check the reason");
  934 + exit( 1 );
  935 + }
  936 + $this->writeLine($result);
  937 + foreach ($output as $value) {
  938 + $this->writeLine($value);
  939 + }
  940 + echo $this->formatMessage("Migration ended successfully", [ 'fg-yellow' ]) . "\n";
  941 + }
  942 +
  943 + /**
  944 + * Write line of code followed by new line symbol
  945 + *
  946 + * @param string $string
  947 + */
  948 + private function writeLine(string $string)
  949 + {
  950 + echo $string . "\n";
  951 + }
  952 +
  953 + /**
  954 + * Perform user creation if input param user doesn't set to 'no'
  955 + */
  956 + private function createUser()
  957 + {
  958 + $params = $this->getParams();
  959 + if (!isset( $params[ 'defaultuser' ] )) {
  960 + if ($this->getParamValue('user') == 'no') {
  961 + echo $this->formatMessage(
  962 + "User creation skipped by user. Run command 'php yii user/create' manually to create user.",
  963 + [
  964 + 'bg-yellow',
  965 + 'bold',
  966 + ]
  967 + ) . "\n";
  968 + exit( 0 );
  969 + }
  970 + do {
  971 + echo " Do you want to create user? [yes|no]";
  972 + $answer = trim(fgets(STDIN));
  973 + } while (strncasecmp($answer, 'y', 1) !== 0 && strncasecmp($answer, 'n', 1) !== 0);
  974 + if (strncasecmp($answer, 'n', 1) === 0) {
  975 + echo $this->formatMessage(
  976 + "User creation skipped by user. Run command 'php yii user/create' manually to create user.",
  977 + [
  978 + 'bg-yellow',
  979 + 'bold',
  980 + ]
  981 + ) . "\n";
  982 + exit( 0 );
  983 + }
  984 + echo "\n Enter username: ";
  985 + $username = trim(fgets(STDIN));
  986 + echo "\n Enter email: ";
  987 + $email = trim(fgets(STDIN));
  988 + echo "\n Enter password: ";
  989 + $password = trim(fgets(STDIN));
  990 + echo "\n";
  991 + $result = exec("php yii create/user $username $email $password", $output, $return);
  992 + } else {
  993 + $result = exec("php yii create/user", $output, $return);
  994 + }
  995 + $this->handleUserCreation($result, $output, $return);
  996 + }
  997 +
  998 + /**
  999 + * Handle user creation result
  1000 + *
  1001 + * @param string $result
  1002 + * @param array $output
  1003 + * @param int $return
  1004 + */
  1005 + private function handleUserCreation($result, $output, $return)
  1006 + {
  1007 + if ($return !== 0) {
  1008 + $this->printError("User cannot be created. Run 'php yii create/user' manually to check the reason");
  1009 + exit( 1 );
  1010 + }
  1011 + $this->writeLine($result);
  1012 + echo $this->formatMessage("User created successfully", [ 'fg-yellow' ]) . "\n";
  1013 + }
  1014 +
  1015 + /**
  1016 + * Congratulate with successfull installation and optionally open browser
  1017 + */
  1018 + private function congratulate()
  1019 + {
  1020 + echo "\n" . $this->formatMessage(
  1021 + "Congratulations. Artbox Basic has been successfully installed.",
  1022 + [
  1023 + 'fg-yellow',
  1024 + 'bold',
  1025 + ]
  1026 + ) . "\n";
  1027 + $url = $this->getParamValue('o');
  1028 + if (!empty( $url )) {
  1029 + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
  1030 + shell_exec("explorer '{$url}'");
  1031 + } else {
  1032 + shell_exec("sensible-browser {$url}");
  1033 + }
  1034 + }
  1035 + }
  1036 + }
  1037 +
0 1038 \ No newline at end of file
... ...
common/config/.gitignore
1 1 main-local.php
  2 +db*
2 3 params-local.php
3 4 test-local.php
4 5 settings.php
5 6 \ No newline at end of file
... ...
console/controllers/CreateController.php
... ... @@ -12,18 +12,30 @@
12 12 */
13 13 class CreateController extends Controller
14 14 {
15   - public function actionUser()
  15 + public function actionUser($username = null, $email = null, $password = null)
16 16 {
17   - $user = new User();
18   - $user->username = 'admin';
19   - $user->email = 'admin@example.com';
20   - $user->setPassword('admin321');
  17 + $username = $username ? : 'admin';
  18 + $user = User::find()
  19 + ->where([ 'username' => $username ])
  20 + ->one();
  21 + if (empty( $user )) {
  22 + $user = new User();
  23 + $user->username = $username;
  24 + }
  25 + $user->email = $email ? : 'admin@example.com';
  26 + $user->setPassword($password ? : 'admin321');
21 27 $user->generateAuthKey();
22 28  
23 29 if ($user->save()) {
24   - $this->stdout('User created' . "\n", Console::FG_GREEN);
  30 + if ($user->isNewRecord) {
  31 + $this->stdout('User created' . "\n", Console::FG_GREEN);
  32 + } else {
  33 + $this->stdout('User updated' . "\n", Console::FG_GREEN);
  34 + }
25 35 } else {
26 36 $this->stdout('Error!' . "\n", Console::FG_RED);
  37 + return self::EXIT_CODE_ERROR;
27 38 }
  39 + return self::EXIT_CODE_NORMAL;
28 40 }
29 41 }
30 42 \ No newline at end of file
... ...
environments/dbmysql.php 0 → 100644
  1 +<?php
  2 + return [
  3 + 'class' => 'yii\db\Connection',
  4 + 'dsn' => '',
  5 + 'username' => '',
  6 + 'password' => '',
  7 + 'charset' => 'utf8',
  8 + ];
  9 + //mysql:host=localhost;dbname=yii2advanced
0 10 \ No newline at end of file
... ...
environments/dbpostgresql.php 0 → 100644
  1 +<?php
  2 + return [
  3 + 'class' => 'yii\db\Connection',
  4 + 'dsn' => '',
  5 + 'username' => '',
  6 + 'password' => '',
  7 + 'charset' => 'utf8',
  8 + 'schemaMap' => [
  9 + 'pgsql' => [
  10 + 'class' => 'yii\db\pgsql\Schema',
  11 + 'defaultSchema' => '',
  12 + ],
  13 + ],
  14 + ];
  15 + //DSN: pgsql:host=127.0.0.1;port=5432;dbname=name
0 16 \ No newline at end of file
... ...
environments/dev/common/config/main-local.php
1 1 <?php
2 2 return [
3 3 'components' => [
4   - 'db' => [
5   - 'class' => 'yii\db\Connection',
6   - 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
7   - 'username' => 'root',
8   - 'password' => '',
9   - 'charset' => 'utf8',
10   - ],
  4 + 'db' => '',
11 5 'mailer' => [
12 6 'class' => 'yii\swiftmailer\Mailer',
13 7 'viewPath' => '@common/mail',
... ...
environments/index.php
... ... @@ -30,14 +30,14 @@
30 30 */
31 31 return [
32 32 'Development' => [
33   - 'path' => 'dev',
34   - 'setWritable' => [
  33 + 'path' => 'dev',
  34 + 'setWritable' => [
35 35 'backend/runtime',
36 36 'backend/web/assets',
37 37 'frontend/runtime',
38 38 'frontend/web/assets',
39 39 ],
40   - 'setExecutable' => [
  40 + 'setExecutable' => [
41 41 'yii',
42 42 'yii_test',
43 43 ],
... ... @@ -45,21 +45,23 @@ return [
45 45 'backend/config/main-local.php',
46 46 'frontend/config/main-local.php',
47 47 ],
  48 + 'setDbConnection' => 'common/config/main-local.php',
48 49 ],
49 50 'Production' => [
50   - 'path' => 'prod',
51   - 'setWritable' => [
  51 + 'path' => 'prod',
  52 + 'setWritable' => [
52 53 'backend/runtime',
53 54 'backend/web/assets',
54 55 'frontend/runtime',
55 56 'frontend/web/assets',
56 57 ],
57   - 'setExecutable' => [
  58 + 'setExecutable' => [
58 59 'yii',
59 60 ],
60 61 'setCookieValidationKey' => [
61 62 'backend/config/main-local.php',
62 63 'frontend/config/main-local.php',
63 64 ],
  65 + 'setDbConnection' => 'common/config/main-local.php',
64 66 ],
65 67 ];
... ...
environments/prod/common/config/main-local.php
1 1 <?php
2 2 return [
3 3 'components' => [
4   - 'db' => [
5   - 'class' => 'yii\db\Connection',
6   - 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
7   - 'username' => 'root',
8   - 'password' => '',
9   - 'charset' => 'utf8',
10   - ],
  4 + 'db' => '',
11 5 'mailer' => [
12 6 'class' => 'yii\swiftmailer\Mailer',
13 7 'viewPath' => '@common/mail',
... ...
1 1 #!/usr/bin/env php
2 2 <?php
3   -/**
4   - * Yii Application Initialization Tool
5   - *
6   - * In order to run in non-interactive mode:
7   - *
8   - * init --env=Development --overwrite=n
9   - *
10   - * @author Alexander Makarov <sam@rmcreative.ru>
11   - *
12   - * @link http://www.yiiframework.com/
13   - * @copyright Copyright (c) 2008 Yii Software LLC
14   - * @license http://www.yiiframework.com/license/
15   - */
16   -
17   -if (!extension_loaded('openssl')) {
18   - die('The OpenSSL PHP extension is required by Yii2.');
19   -}
20   -
21   -$params = getParams();
22   -$root = str_replace('\\', '/', __DIR__);
23   -$envs = require("$root/environments/index.php");
24   -$envNames = array_keys($envs);
25   -
26   -echo "Yii Application Initialization Tool v1.0\n\n";
27   -
28   -$envName = null;
29   -if (empty($params['env']) || $params['env'] === '1') {
30   - echo "Which environment do you want the application to be initialized in?\n\n";
31   - foreach ($envNames as $i => $name) {
32   - echo " [$i] $name\n";
33   - }
34   - echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
35   - $answer = trim(fgets(STDIN));
36   -
37   - if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) {
38   - echo "\n Quit initialization.\n";
39   - exit(0);
40   - }
41   -
42   - if (isset($envNames[$answer])) {
43   - $envName = $envNames[$answer];
44   - }
45   -} else {
46   - $envName = $params['env'];
47   -}
48   -
49   -if (!in_array($envName, $envNames)) {
50   - $envsList = implode(', ', $envNames);
51   - echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n";
52   - exit(2);
53   -}
54   -
55   -$env = $envs[$envName];
56   -
57   -if (empty($params['env'])) {
58   - echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
59   - $answer = trim(fgets(STDIN));
60   - if (strncasecmp($answer, 'y', 1)) {
61   - echo "\n Quit initialization.\n";
62   - exit(0);
63   - }
64   -}
65   -
66   -echo "\n Start initialization ...\n\n";
67   -$files = getFileList("$root/environments/{$env['path']}");
68   -if (isset($env['skipFiles'])) {
69   - $skipFiles = $env['skipFiles'];
70   - array_walk($skipFiles, function(&$value) use($env, $root) { $value = "$root/$value"; });
71   - $files = array_diff($files, array_intersect_key($env['skipFiles'], array_filter($skipFiles, 'file_exists')));
72   -}
73   -$all = false;
74   -foreach ($files as $file) {
75   - if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) {
76   - break;
77   - }
78   -}
79   -
80   -$callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable', 'createSymlink'];
81   -foreach ($callbacks as $callback) {
82   - if (!empty($env[$callback])) {
83   - $callback($root, $env[$callback]);
84   - }
85   -}
86   -
87   -echo "\n ... initialization completed.\n\n";
88   -
89   -function getFileList($root, $basePath = '')
90   -{
91   - $files = [];
92   - $handle = opendir($root);
93   - while (($path = readdir($handle)) !== false) {
94   - if ($path === '.git' || $path === '.svn' || $path === '.' || $path === '..') {
95   - continue;
96   - }
97   - $fullPath = "$root/$path";
98   - $relativePath = $basePath === '' ? $path : "$basePath/$path";
99   - if (is_dir($fullPath)) {
100   - $files = array_merge($files, getFileList($fullPath, $relativePath));
101   - } else {
102   - $files[] = $relativePath;
103   - }
104   - }
105   - closedir($handle);
106   - return $files;
107   -}
108   -
109   -function copyFile($root, $source, $target, &$all, $params)
110   -{
111   - if (!is_file($root . '/' . $source)) {
112   - echo " skip $target ($source not exist)\n";
113   - return true;
114   - }
115   - if (is_file($root . '/' . $target)) {
116   - if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
117   - echo " unchanged $target\n";
118   - return true;
119   - }
120   - if ($all) {
121   - echo " overwrite $target\n";
122   - } else {
123   - echo " exist $target\n";
124   - echo " ...overwrite? [Yes|No|All|Quit] ";
125   -
126   -
127   - $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN));
128   - if (!strncasecmp($answer, 'q', 1)) {
129   - return false;
130   - } else {
131   - if (!strncasecmp($answer, 'y', 1)) {
132   - echo " overwrite $target\n";
133   - } else {
134   - if (!strncasecmp($answer, 'a', 1)) {
135   - echo " overwrite $target\n";
136   - $all = true;
137   - } else {
138   - echo " skip $target\n";
139   - return true;
140   - }
141   - }
142   - }
143   - }
144   - file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
145   - return true;
146   - }
147   - echo " generate $target\n";
148   - @mkdir(dirname($root . '/' . $target), 0777, true);
149   - file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
150   - return true;
151   -}
152   -
153   -function getParams()
154   -{
155   - $rawParams = [];
156   - if (isset($_SERVER['argv'])) {
157   - $rawParams = $_SERVER['argv'];
158   - array_shift($rawParams);
159   - }
160   -
161   - $params = [];
162   - foreach ($rawParams as $param) {
163   - if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
164   - $name = $matches[1];
165   - $params[$name] = isset($matches[3]) ? $matches[3] : true;
166   - } else {
167   - $params[] = $param;
168   - }
169   - }
170   - return $params;
171   -}
172   -
173   -function setWritable($root, $paths)
174   -{
175   - foreach ($paths as $writable) {
176   - if (is_dir("$root/$writable")) {
177   - if (@chmod("$root/$writable", 0777)) {
178   - echo " chmod 0777 $writable\n";
179   - } else {
180   - printError("Operation chmod not permitted for directory $writable.");
181   - }
182   - } else {
183   - printError("Directory $writable does not exist.");
184   - }
185   - }
186   -}
187   -
188   -function setExecutable($root, $paths)
189   -{
190   - foreach ($paths as $executable) {
191   - if (file_exists("$root/$executable")) {
192   - if (@chmod("$root/$executable", 0755)) {
193   - echo " chmod 0755 $executable\n";
194   - } else {
195   - printError("Operation chmod not permitted for $executable.");
196   - }
197   - } else {
198   - printError("$executable does not exist.");
199   - }
200   - }
201   -}
202   -
203   -function setCookieValidationKey($root, $paths)
204   -{
205   - foreach ($paths as $file) {
206   - echo " generate cookie validation key in $file\n";
207   - $file = $root . '/' . $file;
208   - $length = 32;
209   - $bytes = openssl_random_pseudo_bytes($length);
210   - $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
211   - $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file));
212   - file_put_contents($file, $content);
213   - }
214   -}
215   -
216   -function createSymlink($root, $links)
217   -{
218   - foreach ($links as $link => $target) {
219   - //first removing folders to avoid errors if the folder already exists
220   - @rmdir($root . "/" . $link);
221   - //next removing existing symlink in order to update the target
222   - if (is_link($root . "/" . $link)) {
223   - @unlink($root . "/" . $link);
224   - }
225   - if (@symlink($root . "/" . $target, $root . "/" . $link)) {
226   - echo " symlink $root/$target $root/$link\n";
227   - } else {
228   - printError("Cannot create symlink $root/$target $root/$link.");
229   - }
230   - }
231   -}
232   -
233   -/**
234   - * Prints error message.
235   - * @param string $message message
236   - */
237   -function printError($message)
238   -{
239   - echo "\n " . formatMessage("Error. $message", ['fg-red']) . " \n";
240   -}
241   -
242   -/**
243   - * Returns true if the stream supports colorization. ANSI colors are disabled if not supported by the stream.
244   - *
245   - * - windows without ansicon
246   - * - not tty consoles
247   - *
248   - * @return boolean true if the stream supports ANSI colors, otherwise false.
249   - */
250   -function ansiColorsSupported()
251   -{
252   - return DIRECTORY_SEPARATOR === '\\'
253   - ? getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON'
254   - : function_exists('posix_isatty') && @posix_isatty(STDOUT);
255   -}
256   -
257   -/**
258   - * Get ANSI code of style.
259   - * @param string $name style name
260   - * @return integer ANSI code of style.
261   - */
262   -function getStyleCode($name)
263   -{
264   - $styles = [
265   - 'bold' => 1,
266   - 'fg-black' => 30,
267   - 'fg-red' => 31,
268   - 'fg-green' => 32,
269   - 'fg-yellow' => 33,
270   - 'fg-blue' => 34,
271   - 'fg-magenta' => 35,
272   - 'fg-cyan' => 36,
273   - 'fg-white' => 37,
274   - 'bg-black' => 40,
275   - 'bg-red' => 41,
276   - 'bg-green' => 42,
277   - 'bg-yellow' => 43,
278   - 'bg-blue' => 44,
279   - 'bg-magenta' => 45,
280   - 'bg-cyan' => 46,
281   - 'bg-white' => 47,
282   - ];
283   - return $styles[$name];
284   -}
285   -
286   -/**
287   - * Formats message using styles if STDOUT supports it.
288   - * @param string $message message
289   - * @param string[] $styles styles
290   - * @return string formatted message.
291   - */
292   -function formatMessage($message, $styles)
293   -{
294   - if (empty($styles) || !ansiColorsSupported()) {
295   - return $message;
296   - }
297   -
298   - return sprintf("\x1b[%sm", implode(';', array_map('getStyleCode', $styles))) . $message . "\x1b[0m";
299   -}
  3 + /**
  4 + * Yii Application Initialization Tool
  5 + * In order to run in non-interactive mode:
  6 + * init --env=Development --overwrite=n
  7 + *
  8 + * @author Alexander Makarov <sam@rmcreative.ru>
  9 + * @link http://www.yiiframework.com/
  10 + * @copyright Copyright (c) 2008 Yii Software LLC
  11 + * @license http://www.yiiframework.com/license/
  12 + */
  13 + require( 'Initializer.php' );
  14 + if (!extension_loaded('openssl')) {
  15 + die( 'The OpenSSL PHP extension is required by Yii2.' );
  16 + }
  17 +
  18 + Initializer::initialize();
... ...