Issues (90)

src/commands/Init.php (1 issue)

1
<?php
2
3
namespace yentu\commands;
4
5
use clearice\io\Io;
6
use yentu\exceptions\NonReversibleCommandException;
7
use yentu\factories\DatabaseManipulatorFactory;
8
use yentu\Migrations;
9
use yentu\Parameters;
10
use yentu\exceptions\CommandException;
11
use ntentan\utils\Filesystem;
12
13
/**
14
 * The init command class.
15
 * This command initiates a project for yentu by creating the required migration directories and configuration files.
16
 * It also creates the database history table.
17
 */
18
class Init extends Command implements Reversible
19
{
20
    /**
21
     * Instance of io for CLI output
22
     * @var Io
23
     */
24
    private $io;
25
26
    /**
27
     * Provides access to migrations.
28
     * @var Migrations
29
     */
30
    private $migrations;
31
32
    /**
33
     * For performing database operations
34
     * @var DatabaseManipulatorFactory
35
     */
36
    private $manipulatorFactory;
37
38
    /**
39
     * Init constructor.
40
     *
41
     * @param Migrations $migrations
42
     * @param DatabaseManipulatorFactory $manipulatorFactory
43
     * @param Io $io
44
     */
45
    public function __construct(Migrations $migrations, DatabaseManipulatorFactory $manipulatorFactory, Io $io)
46
    {
47
        $this->migrations = $migrations;
48
        $this->io = $io;
49
        $this->manipulatorFactory = $manipulatorFactory;
50
    }
51
52
    /**
53
     * Extract parameters from command line arguments, or through interactive sessions.
54
     * @return array
55
     */
56
    private function getParams() : array
57
    {
58
        if (isset($this->options['interractive'])) {
59
            $params['driver'] = $this->io->getResponse(
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
60
                'What type of database are you working with?', 
61
                ['required' => true, 'answers' => ['postgresql', 'mysql', 'sqlite']]
62
            );
63
64
            if ($params['driver'] === 'sqlite') {
65
                $params['file'] = $this->io->getResponse('What is the path to your database file?', ['required' => true]);
66
            } else {
67
                $params['host'] = $this->io->getResponse('What is the host of your database connection?', ['default' => 'localhost']);
68
                $params['port'] = $this->io->getResponse('What is the port of your database connection? (Leave blank for default)');
69
                $params['user'] = $this->io->getResponse('What username do you connect with?', ['required' => true]);
70
                $params['password'] = $this->io->getResponse("What is the password for {$params['user']}?", ['required' => FALSE]);
71
                $params['dbname'] = $this->io->getResponse("What is the name database (schema) are you connecting to?",['required' => true]);
72
            }
73
        } else {
74
            $params = [];
75
            foreach(['driver', 'file', 'host', 'port', 'dbname', 'user', 'password'] as $key) {
76
                if(isset($this->options[$key])) {
77
                    $params[$key] = $this->options[$key];
78
                }
79
            }
80
        }
81
        return $params;
82
    }
83
84
    /**
85
     * @param $params
86
     * @return array
87
     * @throws \ntentan\utils\exceptions\FileAlreadyExistsException
88
     * @throws \ntentan\utils\exceptions\FileNotWriteableException
89
     */
90
    public function createConfigFile($params) : array
91
    {
92
        $params = Parameters::wrap(
93
            $params, ['port', 'file', 'host', 'dbname', 'user', 'password']
94
        );
95
        Filesystem::directory($this->migrations->getPath('config'))->create(true);
96
        Filesystem::directory($this->migrations->getPath('migrations'))->create(true);
97
        Filesystem::file($this->migrations->getPath('config/yentu.ini'))->putContents(
98
            <<<CONFIG
99
            [db]
100
            driver: {$params['driver']}
101
            host: {$params['host']}
102
            port: {$params['port']}
103
            dbname: {$params['dbname']}
104
            user: {$params['user']}
105
            password: {$params['password']}
106
            file: {$params['file']}
107
            CONFIG
108
        );
109
110
        return $params;
111
    }
112
113
    /**
114
     * @throws CommandException
115
     */
116
    public function run() : void
117
    {
118
        $home = $this->migrations->getPath('');
119
        if (file_exists($home)) {
120
            throw new NonReversibleCommandException("Could not initialize yentu. Your project has already been initialized with yentu.");
121
        } else if (!is_writable(dirname($home))) {
122
            throw new NonReversibleCommandException("Your home directory ($home) could not be created.");
123
        }
124
125
        $params = $this->getParams();
126
        
127
        if (count($params) == 0 && defined('STDOUT')) {
128
            throw new NonReversibleCommandException(
129
                "You didn't provide any parameters for initialization. Please execute yentu "
130
                . "with `init -i` to initialize yentu interractively. "
131
                . "You can also try `init --help` for more information."
132
            );
133
        }
134
135
        $config = $this->createConfigFile($params);
136
        $db = $this->manipulatorFactory->createManipulatorWithConfig($config);
137
138
        if ($db->getAssertor()->doesTableExist('yentu_history')) {
139
            throw new CommandException("Could not initialize yentu. Your database may have been initialized with yentu; the 'yentu_history' table already exists.");
140
        }
141
142
        $db->createHistory();
143
        $db->disconnect();
144
145
        $this->io->output("Yentu successfully initialized.\n");
146
    }
147
148
    public function reverseActions() : void
149
    {
150
        Filesystem::directory($this->migrations->getPath(""))->delete();
151
    }
152
153
}
154