table; } /** * Set the value of table. * * @param string $table * * @return self */ public function setTable(string $table): self { $this->table = $table; return $this; } /** * @param string $table * @param DbArray|array|null $previous * @param DatabaseAbstract $settings * * @return Promise * * @psalm-return Promise */ public static function getInstance(string $table, $previous, $settings): Promise { if ($previous instanceof static && $previous->getTable() === $table) { $instance = &$previous; } else { $instance = new static(); $instance->setTable($table); } /** @psalm-suppress UndefinedPropertyAssignment */ $instance->dbSettings = $settings; $instance->ttl = $settings->getCacheTtl(); $instance->startCacheCleanupLoop(); return call(static function () use ($instance, $previous, $settings) { yield from $instance->initConnection($settings); yield from $instance->prepareTable(); if ($instance !== $previous) { if ($previous instanceof DriverArray) { yield from $previous->initStartup(); } yield from static::renameTmpTable($instance, $previous); if ($instance instanceof SqlArray) { Logger::log("Preparing statements..."); yield from $instance->prepareStatements(); } yield from static::migrateDataToDb($instance, $previous); } elseif ($instance instanceof SqlArray) { Logger::log("Preparing statements..."); yield from $instance->prepareStatements(); } return $instance; }); } /** * Rename table of old database, if the new one is not a temporary table name. * * Otherwise, simply change name of table in new database to match old table name. * * @param self $new New db * @param DbArray|array|null $old Old db * * @return \Generator */ protected static function renameTmpTable(self $new, $old): \Generator { if ($old instanceof static && $old->getTable()) { if ( $old->getTable() !== $new->getTable() && \mb_strpos($new->getTable(), 'tmp') !== 0 ) { yield from $new->renameTable($old->getTable(), $new->getTable()); } else { $new->setTable($old->getTable()); } } } /** * @param self $new * @param DbArray|array|null $old * * @return \Generator * @throws \Throwable */ protected static function migrateDataToDb(self $new, $old): \Generator { if (!empty($old) && !$old instanceof static) { Logger::log('Converting database to '.\get_class($new), Logger::ERROR); if ($old instanceof DbArray) { $old = yield $old->getArrayCopy(); } else { $old = (array) $old; } $counter = 0; $total = \count($old); foreach ($old as $key => $item) { $counter++; if ($counter % 500 === 0) { yield $new->offsetSet($key, $item); Logger::log("Loading data to table {$new}: $counter/$total", Logger::WARNING); } else { $new->offsetSet($key, $item); } } Logger::log('Converting database done.', Logger::ERROR); } } public function __destruct() { $this->stopCacheCleanupLoop(); } /** * Get the value of table. * * @return string */ public function __toString(): string { return $this->table; } /** * Sleep function. * * @return array */ public function __sleep(): array { return ['table', 'dbSettings']; } public function __wakeup() { if (isset($this->settings) && \is_array($this->settings)) { $clazz = (new ReflectionClass($this))->getProperty('dbSettings')->getType()->getName(); /** * @var SettingsAbstract * @psalm-suppress UndefinedThisPropertyAssignment */ $this->dbSettings = new $clazz; $this->dbSettings->mergeArray($this->settings); unset($this->settings); } } public function offsetExists($index): bool { throw new \RuntimeException('Native isset not support promises. Use isset method'); } }