ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilDatabasePopulatedObjective.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
21 use ILIAS\Setup;
24 
26 {
27  public const MIN_NUMBER_OF_ILIAS_TABLES = 200; // educated guess
28 
29  public function getHash(): string
30  {
31  return hash("sha256", implode("-", [
32  self::class,
33  $this->config->getHost(),
34  $this->config->getPort(),
35  $this->config->getDatabase()
36  ]));
37  }
38 
39  public function getLabel(): string
40  {
41  return "The database is populated with ILIAS-tables.";
42  }
43 
44  public function isNotable(): bool
45  {
46  return true;
47  }
48 
52  public function getPreconditions(Setup\Environment $environment): array
53  {
54  if ($environment->hasConfigFor(Setup\CLI\InstallCommand::IMPORT)) {
55  return [new ObjectiveWithPreconditions(
56  new \ilDatabaseExistsObjective($this->config),
57  new ImportFileUnzippedFileObjective($environment->getConfigFor(Setup\CLI\InstallCommand::IMPORT))
58  )];
59  }
60  if ($environment->getResource(Setup\Environment::RESOURCE_DATABASE)) {
61  return [];
62  }
63  return [
64  new \ilDatabaseExistsObjective($this->config)
65  ];
66  }
67 
68  public function achieve(Setup\Environment $environment): Setup\Environment
69  {
74  $db = $environment->getResource(Setup\Environment::RESOURCE_DATABASE);
75  $io = $environment->getResource(Setup\Environment::RESOURCE_ADMIN_INTERACTION);
76 
77  // $this->setDefaultEngine($db); // maybe we could set the default?
78  $default = $this->getDefaultEngine($db);
79 
80  $io->text("Default DB engine is $default");
81 
82 
83  switch ($default) {
84  case 'innodb':
85  $io->text("reading dump file, this may take a while...");
86  $this->readDumpFile($db);
87  break;
88 
89  default:
90  throw new Setup\UnachievableException(
91  "Cannot determine database default engine, must be InnoDB, `$default` given."
92  );
93  }
94 
95  return $environment;
96  }
97 
101  public function isApplicable(Setup\Environment $environment): bool
102  {
103  if ($environment->hasConfigFor(Setup\CLI\InstallCommand::IMPORT)) {
104  return true;
105  }
106 
107  $db = $environment->getResource(Setup\Environment::RESOURCE_DATABASE);
108 
109  return !$this->isDatabasePopulated($db);
110  }
111 
112  protected function isDatabasePopulated(ilDBInterface $db): bool
113  {
114  $probe_tables = ['usr_data', 'object_data', 'object_reference'];
115  $number_of_probe_tables = count($probe_tables);
116  $tables = $db->listTables();
117  $number_of_tables = count($tables);
118 
119  return
120  $number_of_tables > self::MIN_NUMBER_OF_ILIAS_TABLES
121  && count(array_intersect($tables, $probe_tables)) === $number_of_probe_tables;
122  }
123 
127  private function readDumpFile(ilDBInterface $db): void
128  {
129  $path_to_db_dump = $this->config->getPathToDBDump();
130  if (!is_file(realpath($path_to_db_dump)) ||
131  !is_readable(realpath($path_to_db_dump))) {
132  throw new Setup\UnachievableException(
133  "Cannot read database dump file: $path_to_db_dump"
134  );
135  }
136  foreach ($this->queryReader(realpath($path_to_db_dump)) as $query) {
137  try {
138  $statement = $db->prepareManip($query);
139  $db->execute($statement);
140  } catch (Throwable $e) {
141  throw new Setup\UnachievableException(
142  "Cannot populate database with dump file: $path_to_db_dump. Query failed: $query wih message " . $e->getMessage(
143  )
144  );
145  }
146  }
147  }
148 
149  private function queryReader(string $path_to_db_dump): Generator
150  {
151  $stack = '';
152  $handle = fopen($path_to_db_dump, "r");
153  while (($line = fgets($handle)) !== false) {
154  if (preg_match('/^--/', $line)) { // Skip comments
155  continue;
156  }
157  if (preg_match('/^\/\*/', $line)) { // Run Variables Assignments as single query
158  yield $line;
159  $stack = '';
160  continue;
161  }
162  if (!preg_match('/;$/', trim($line))) { // Break after ; character which indicates end of query
163  $stack .= $line;
164  } else {
165  $stack .= $line;
166  yield $stack;
167  $stack = '';
168  }
169  }
170 
171  fclose($handle);
172  }
173 
178  private function setDefaultEngine(ilDBInterface $db): void
179  {
180  switch ($db->getDBType()) {
181  case 'pdo-mysql-innodb':
185  $db->manipulate('SET default_storage_engine=InnoDB;');
186  break;
187  }
188  }
189 
190  private function getDefaultEngine(ilDBInterface $db): string
191  {
192  try {
193  $r = $db->query('SHOW ENGINES ');
194 
195  $default = '';
196  while ($d = $db->fetchObject($r)) {
197  if (strtoupper($d->Support) === 'DEFAULT') {
198  $default = $d->Engine;
199  break;
200  }
201  }
202  return strtolower($default);
203  } catch (Throwable $e) {
204  return 'unknown';
205  }
206  }
207 }
getPreconditions(Setup\Environment $environment)
A wrapper around an objective that adds some preconditions.
execute(ilDBStatement $stmt, array $data=[])
fetchObject(ilDBStatement $query_result)
query(string $query)
Run a (read-only) Query on the database.
getDBType()
Get DSN.
isApplicable(Setup\Environment $environment)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
prepareManip(string $a_query, ?array $a_types=null)
An environment holds resources to be used in the setup process.
Definition: Environment.php:27
manipulate(string $query)
Run a (write) Query on the database.
$r