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