From 15793496e8d56769c792cf39673c6e6dea3ec4d9 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Thu, 28 Jun 2018 21:15:57 +0200 Subject: Preparing for complete rewrite.. --- main/app/system/Bakery/Migrator.php | 570 ------------------------------------ 1 file changed, 570 deletions(-) delete mode 100644 main/app/system/Bakery/Migrator.php (limited to 'main/app/system/Bakery/Migrator.php') diff --git a/main/app/system/Bakery/Migrator.php b/main/app/system/Bakery/Migrator.php deleted file mode 100644 index 568febd..0000000 --- a/main/app/system/Bakery/Migrator.php +++ /dev/null @@ -1,570 +0,0 @@ -io = $io; - $this->ci = $ci; - - // Start by testing the DB connexion, just in case - try { - $this->io->writeln("Testing database connection", OutputInterface::VERBOSITY_VERBOSE); - $this->testDB(); - $this->io->writeln("Ok", OutputInterface::VERBOSITY_VERBOSE); - } catch (\Exception $e) { - $this->io->error($e->getMessage()); - exit(1); - } - - // Get schema required to run the table blueprints - $this->schema = Capsule::schema(); - - // Make sure the setup table exist - $this->setupVersionTable(); - } - - /** - * Run all the migrations available - * - * @access public - * @param bool $pretend (default: false) - * @return void - */ - public function runUp($pretend = FALSE) { - // Get installed migrations and pluck by class name. We only need this for now - $migrations = Migrations::get(); - $this->installed = $migrations->pluck('migration'); - - $this->io->writeln("\nInstalled migrations:", OutputInterface::VERBOSITY_VERBOSE); - $this->io->writeln($this->installed->toArray(), OutputInterface::VERBOSITY_VERBOSE); - - // Get pending migrations - $this->io->section("Fetching available migrations"); - $this->pending = $this->getPendingMigrations(); - - // If there's no pending migration, don't need to go further - if ($this->pending->isEmpty()) { - $this->io->success("Nothing to migrate !"); - return; - } - - // Resolve the dependencies - $this->resolveDependencies(); - - // If there are any unfulfillable migration, we can't continue - if (!$this->unfulfillable->isEmpty()) { - - $msg = "\nSome migrations dependencies can't be met. Check those migrations for unmet dependencies and try again:"; - - foreach ($this->unfulfillable as $migration) { - $msg .= "\n{$migration->className} depends on \n - "; - $msg .= implode("\n - ", $migration->dependencies); - $msg .= "\n"; - } - - $this->io->error($msg); - exit(1); - } - - // Ready to run ! - $this->io->section("Running migrations"); - - if ($pretend) { - $this->io->note("Running migration in pretend mode"); - } - - // We have a list of fulfillable migration, we run them up! - foreach ($this->fulfillable as $migration) { - $this->io->write("\n> Migrating {$migration->className}..."); - - if ($pretend) { - $this->io->newLine(); - $this->pretendToRun($migration, 'up'); - } else { - $migration->up(); - $migration->seed(); - $this->log($migration); - $this->io->writeln(" Done!"); - } - } - - // If all went well and there's no fatal errors, we are ready to bake - $this->io->success("Migration successful !"); - } - - /** - * Rollback the last btach of migrations. - * - * @access public - * @param int $step (default: 1). Number of batch we will be going back. -1 revert all migrations - * @param string $sprinkle (default: "") Limit rollback to a specific sprinkle - * @param bool $pretend (default: false) - * @return void - */ - public function runDown($step = 1, $sprinkle = "", $pretend = FALSE) { - // Can't go furhter down than 1 step - if ($step <= 0 && $step != -1) { - throw new \InvalidArgumentException("Step can't be 0 or less"); - } - - // Get last batch number - $batch = $this->getNextBatchNumber(); - - // Calculate the number of steps back we need to take - if ($step == -1) { - $stepsBack = 1; - $this->io->warning("Rolling back all migrations"); - } else { - $stepsBack = max($batch - $step, 1); - $this->io->note("Rolling back $step steps to batch $stepsBack", OutputInterface::VERBOSITY_VERBOSE); - } - - // Get installed migrations - $migrations = Migrations::orderBy("id", "desc")->where('batch', '>=', $stepsBack); - - // Add the sprinkle requirement too - if ($sprinkle != "") { - $this->io->note("Rolling back sprinkle `$sprinkle`", OutputInterface::VERBOSITY_VERBOSE); - $migrations->where('sprinkle', $sprinkle); - } - - // Run query - $migrations = $migrations->get(); - - // If there's nothing to rollback, stop here - if ($migrations->isEmpty()) { - $this->io->writeln("Nothing to rollback"); - exit(1); - } - - // Get pending migrations - $this->io->writeln("Migration to rollback:"); - $this->io->listing($migrations->pluck('migration')->toArray()); - - // Ask confirmation to continue. - if (!$pretend && !$this->io->confirm("Continue?", FALSE)) { - exit(1); - } - - if ($pretend) { - $this->io->note("Rolling back in pretend mode"); - } - - // Loop again to run down each migration - foreach ($migrations as $migration) { - - // Check if those migration class are available - if (!class_exists($migration->migration)) { - $this->io->warning("Migration class {$migration->migration} doesn't exist."); - continue; - } - - $this->io->write("> Rolling back {$migration->migration}..."); - $migrationClass = $migration->migration; - $instance = new $migrationClass($this->schema, $this->io); - - if ($pretend) { - $this->io->newLine(); - $this->pretendToRun($instance, 'down'); - } else { - $instance->down(); - $migration->delete(); - $this->io->writeln(" Done!"); - } - - $this->io->newLine(); - } - - // If all went well and there's no fatal errors, we are ready to bake - $this->io->success("Rollback successful !"); - } - - /** - * Pretend to run migration class. - * - * @access protected - * @param mixed $migration - * @param string $method up/down - */ - protected function pretendToRun($migration, $method) { - foreach ($this->getQueries($migration, $method) as $query) { - $this->io->writeln($query['query'], OutputInterface::VERBOSITY_VERBOSE); - } - } - - /** - * Return all of the queries that would be run for a migration. - * - * @access protected - * @param mixed $migration - * @param string $method up/down - * @return void - */ - protected function getQueries($migration, $method) { - $db = $this->schema->getConnection(); - - return $db->pretend(function () use ($migration, $method) { - if (method_exists($migration, $method)) { - $migration->{$method}(); - } - }); - } - - /** - * Get pending migrations by looking at all the migration files - * and finding the one not yet runed by compairing with the ran migrations - * - * @access protected - * @return void - */ - protected function getPendingMigrations() { - $pending = collect([]); - - // Get the sprinkle list - $sprinkles = $this->ci->sprinkleManager->getSprinkleNames(); - - // Loop all the sprinkles to find their pending migrations - foreach ($sprinkles as $sprinkle) { - - $this->io->writeln("> Fetching from `$sprinkle`"); - - // We get all the migrations. This will return them as a colleciton of class names - $migrations = $this->getMigrations($sprinkle); - - // We filter the available migration by removing the one that have already been run - // This reject the class name found in the installed collection - $migrations = $migrations->reject(function ($value, $key) { - return $this->installed->contains($value); - }); - - // Load each class - foreach ($migrations as $migrationClass) { - - // Make sure the class exist - if (!class_exists($migrationClass)) { - throw new BadClassNameException("Unable to find the migration class '$migrationClass'."); - } - - // Load the migration class - $migration = new $migrationClass($this->schema, $this->io); - - //Set the sprinkle - $migration->sprinkle = $sprinkle; - - // Also set the class name. We could find it using ::class, but this - // will make it easier to manipulate the collection - $migration->className = $migrationClass; - - // Add it to the pending list - $pending->push($migration); - } - } - - // Get pending migrations - $pendingArray = ($pending->pluck('className')->toArray()) ?: ""; - $this->io->writeln("\nPending migrations:", OutputInterface::VERBOSITY_VERBOSE); - $this->io->writeln($pendingArray, OutputInterface::VERBOSITY_VERBOSE); - - return $pending; - } - - /** - * Get the list of migrations avaiables in the filesystem. - * Return a list of resolved className - * - * @access public - * @param string $sprinkleName - * @return void - */ - public function getMigrations($sprinkle) { - // Find all the migration files - $path = $this->migrationDirectoryPath($sprinkle); - $files = glob($path . "*/*.php"); - - // Transform the array in a collection - $migrations = collect($files); - - // We transform the path into a migration object - $migrations->transform(function ($file) use ($sprinkle, $path) { - // Deconstruct the path - $migration = str_replace($path, "", $file); - $className = basename($file, '.php'); - $sprinkleName = Str::studly($sprinkle); - $version = str_replace("/$className.php", "", $migration); - - // Reconstruct the classname - $className = "\\UserFrosting\\Sprinkle\\" . $sprinkleName . "\\Database\\Migrations\\" . $version . "\\" . $className; - - return $className; - }); - - return $migrations; - } - - /** - * Resolve all the dependencies for all the pending migrations - * This function fills in the `fullfillable` and `unfulfillable` list - * - * @access protected - * @return void - */ - protected function resolveDependencies() { - $this->io->writeln("\nResolving migrations dependencies...", OutputInterface::VERBOSITY_VERBOSE); - - // Reset fulfillable/unfulfillable lists - $this->fulfillable = collect([]); - $this->unfulfillable = collect([]); - - // Loop pending and check for dependencies - foreach ($this->pending as $migration) { - $this->validateClassDependencies($migration); - } - - $fulfillable = ($this->fulfillable->pluck('className')->toArray()) ?: ""; - $this->io->writeln("\nFulfillable migrations:", OutputInterface::VERBOSITY_VERBOSE); - $this->io->writeln($fulfillable, OutputInterface::VERBOSITY_VERBOSE); - - $unfulfillable = ($this->unfulfillable->pluck('className')->toArray()) ?: ""; - $this->io->writeln("\nUnfulfillable migrations:", OutputInterface::VERBOSITY_VERBOSE); - $this->io->writeln($unfulfillable, OutputInterface::VERBOSITY_VERBOSE); - } - - /** - * Check if a migration dependencies are met. - * To test if a migration is fulfillable, the class must : - * Already been installed OR exist and have all it's dependencies met - * - * @access protected - * @param $migration - * @return bool true/false if all conditions are met - */ - protected function validateClassDependencies($migration) { - $this->io->writeln("> Checking dependencies for {$migration->className}", OutputInterface::VERBOSITY_VERBOSE); - - // If it's already marked as fulfillable, it's fulfillable - // Return true directly (it's already marked) - if ($this->fulfillable->contains($migration)) { - return TRUE; - } - - // If it's already marked as unfulfillable, it's unfulfillable - // Return false directly (it's already marked) - if ($this->unfulfillable->contains($migration)) { - return FALSE; - } - - // If it's already run, it's fulfillable - // Mark it as such for next time it comes up in this loop - if ($this->installed->contains($migration->className)) { - return $this->markAsFulfillable($migration); - } - - // Loop dependencies. If one is not fulfillable, then this one is not either - foreach ($migration->dependencies as $dependencyClass) { - - // The dependency might already be installed. Check that first - if ($this->installed->contains($dependencyClass)) { - continue; - } - - // Try to find it in the `pending` list. Cant' find it? Then it's not fulfillable - $dependency = $this->pending->where('className', $dependencyClass)->first(); - - // Check migration dependencies of this one right now - // If ti's not fullfillable, then this one isn't either - if (!$dependency || !$this->validateClassDependencies($dependency)) { - return $this->markAsUnfulfillable($migration); - } - } - - // If no dependencies returned false, it's fulfillable - return $this->markAsFulfillable($migration); - } - - /** - * Mark a dependency as fulfillable. - * Removes it from the pending list and add it to the fulfillable list - * - * @access protected - * @param $migration - * @return true - */ - protected function markAsFulfillable($migration) { - $this->fulfillable->push($migration); - return TRUE; - } - - /** - * Mark a dependency as unfulfillable. - * Removes it from the pending list and add it to the unfulfillable list - * - * @access protected - * @param $migration - * @return false - */ - protected function markAsUnfulfillable($migration) { - $this->unfulfillable->push($migration); - return FALSE; - } - - /** - * Log that a migration was run. - * - * @access public - * @param mixed $migration - * @return void - */ - protected function log($migration) { - // Get the next batch number if not defined - if (!$this->batch) { - $this->batch = $this->getNextBatchNumber(); - } - - $log = new Migrations([ - 'sprinkle' => $migration->sprinkle, - 'migration' => $migration->className, - 'batch' => $this->batch - ]); - $log->save(); - } - - /** - * Return the next batch number from the db. - * Batch number is used to group together migration run in the same operation - * - * @access public - * @return int the next batch number - */ - public function getNextBatchNumber() { - $batch = Migrations::max('batch'); - return ($batch) ? $batch + 1 : 1; - } - - /** - * Create the migration history table if needed. - * Also check if the tables requires migrations - * We run the migration file manually for this one - * - * @access public - * @return void - */ - protected function setupVersionTable() { - // Check if the `migrations` table exist. Create it manually otherwise - if (!$this->schema->hasColumn($this->table, 'id')) { - $this->io->section("Creating the `{$this->table}` table"); - - $migration = new \UserFrosting\System\Database\Migrations\v410\MigrationTable($this->schema, $this->io); - $migration->up(); - - $this->io->success("Table `{$this->table}` created"); - } - } - - /** - * Returns the path of the Migration directory. - * - * @access protected - * @param mixed $sprinkleName - * @return void - */ - protected function migrationDirectoryPath($sprinkleName) { - $path = \UserFrosting\SPRINKLES_DIR . - \UserFrosting\DS . - $sprinkleName . - \UserFrosting\DS . - \UserFrosting\SRC_DIR_NAME . - "/Database/Migrations/"; - - return $path; - } -} -- cgit v1.2.3