/** * Determines if the current entry is a valid SQL update file. * * @return bool */ public function accept() { /** @var \DirectoryIterator $this */ $filename = $this->getFilename(); if (!$this->isFile() || substr($filename, -4) != '.php' || preg_match('/^sql_(\\d{8}_\\d{6})/', $filename) === 0) { return false; } try { $check = Helper::checkFiles($this->getPath(), array($filename)); if (count($check) == 0) { return false; } } catch (DeployException $exception) { return false; } return true; }
/** * Check if the db_patches table exists, compare it to the locally available patches and ask the user what he wants to do if there's a difference. * * @param string $action update of rollback * @throws \LemonWeb\Deployer\Exceptions\DeployException */ public function check($action) { $this->logger->log('Check for database updates:', LOG_INFO, true); if (empty($this->database_dirs)) { return; } // collect and verify the database login information so the db_patches table can be checked $this->getDatabaseLogin(true); // make a list of all available patchfiles in de project $available_patches = $this->findSQLFiles($action); $patches_to_apply = array(); $patches_to_revert = array(); $patches_to_register_as_done = array(); $performed_patches = array(); $dependencies = array(); if ($this->patches_table_exists = $this->checkIfPatchTableExists()) { // get the list of all performed patches from the database list($performed_patches, $dependencies) = $this->findPerformedSQLPatches(); if (Deploy::UPDATE == $action) { // list the patches that have not yet been applied $patches_to_apply = array_diff_key($available_patches, $performed_patches); // list the patches that have been removed from the project and may need to be reverted $patches_to_revert = array_diff_key($performed_patches, $available_patches); } elseif (Deploy::ROLLBACK == $action) { // find the patches that have been performed on the previous deploy foreach ($performed_patches as $datetime => $applied_at) { if (($timestamp = strtotime($applied_at)) && $timestamp > $this->previous_timestamp && $timestamp <= $this->last_timestamp) { $patches_to_revert[$datetime] = $datetime; } } } } else { if (Deploy::UPDATE == $action) { // make a list of all patches that could be considered as already applied $patches_to_apply = $available_patches; } } // nothing needs to be done if (empty($patches_to_apply) && empty($patches_to_revert) && empty($patches_to_register_as_done)) { $this->logger->log('Database is up to date !'); return; } ksort($patches_to_apply, SORT_STRING); krsort($patches_to_revert, SORT_STRING); ksort($patches_to_register_as_done, SORT_STRING); // check if the files all contain SQL patches and filter out inactive patches $patches_to_apply = array_intersect($patches_to_apply, array_keys(Helper::checkFiles($this->basedir, $patches_to_apply))); $patches_to_apply = $this->checkDependencies($patches_to_apply, $performed_patches); $patches_to_revert = $this->checkRevertDependencies($patches_to_revert, $dependencies); if (!empty($patches_to_revert)) { if (!empty($patches_to_revert)) { $this->logger->log('Database patches to revert (' . count($patches_to_revert) . '): ' . PHP_EOL . implode(PHP_EOL, array_keys($patches_to_revert))); if (count($patches_to_revert) > 1) { $choice = $this->local_shell->inputPrompt('Revert ? (Y/p/n): ', 'y', false, array('y', 'p', 'n')); } else { $choice = $this->local_shell->inputPrompt('Revert ? (Y/n): ', 'y', false, array('y', 'n')); } if ('y' == $choice) { $this->patches_to_revert += $patches_to_revert; } elseif ('p' == $choice) { list($chosen_patches_to_revert) = $this->pickPatches($patches_to_revert, array('y', 'n')); // if the hand-chosen list introduced dependency problems, prompt the user $checked_patches_to_revert = $this->checkRevertDependencies($chosen_patches_to_revert, $dependencies); if (count($checked_patches_to_revert) > 0 && count($checked_patches_to_revert) != count($chosen_patches_to_revert)) { if ('y' == $this->local_shell->inputPrompt('Are you sure ? (y/N): ', 'n', false, array('y', 'n'))) { $this->patches_to_revert += $checked_patches_to_revert; } } else { $this->patches_to_revert += $checked_patches_to_revert; } } } } if (!empty($patches_to_apply)) { if (!empty($patches_to_apply)) { $patches_list = 'Database patches to apply (' . count($patches_to_apply) . '): ' . PHP_EOL; foreach ($patches_to_apply as $patch_filename) { $patches_list .= $patch_filename; $patch_classname = Helper::getClassnameFromFilepath($patch_filename); /** @var AbstractSqlUpdate $patch */ $patch = new $patch_classname(array('charset' => $this->database_charset)); if ($patch->getType() == SqlUpdateInterface::TYPE_LARGE) { $patches_list .= " [01;31m[Large][0m"; } $patches_list .= PHP_EOL; } $this->logger->log($patches_list); // only offer to register patches as done if the patches table exists if ($this->patches_table_exists) { if (count($patches_to_apply) > 1) { $choice = $this->local_shell->inputPrompt('[a]pply, [r]egister as done, [p]ick, [i]gnore (A/r/p/i): ', 'a', false, array('a', 'r', 'p', 'i')); } else { $choice = $this->local_shell->inputPrompt('[a]pply, [r]egister as done, [i]gnore (A/r/i): ', 'a', false, array('a', 'r', 'i')); } } else { if (count($patches_to_apply) > 1) { $choice = $this->local_shell->inputPrompt('[a]pply, [p]ick, [i]gnore (A/p/i): ', 'a', false, array('a', 'p', 'i')); } else { $choice = $this->local_shell->inputPrompt('[a]pply, [i]gnore (A/i): ', 'a', false, array('a', 'i')); } } if ('a' == $choice) { $this->patches_to_apply += $patches_to_apply; } elseif ('r' == $choice) { $this->patches_to_register_as_done += $patches_to_apply; } elseif ('p' == $choice) { list($picked_apply, $picked_register) = $this->pickPatches($patches_to_apply, array('a', 'r', 'i'), 'a'); // if the hand-chosen list introduced dependency problems, prompt the user $checked_patches_to_apply = $this->checkDependencies($picked_apply, $performed_patches + $picked_register); if (count($checked_patches_to_apply) > 0 && count($checked_patches_to_apply) != count($picked_apply)) { if ('y' == $this->local_shell->inputPrompt('Are you sure ? (y/N)', 'n', false, array('y', 'n'))) { $this->patches_to_apply += $picked_apply; $this->patches_to_register_as_done += $picked_register; } } else { $this->patches_to_apply += $checked_patches_to_apply; $this->patches_to_register_as_done += $picked_register; } } } } if (!empty($patches_to_register_as_done)) { $patches_to_register_as_done = $this->checkDependencies($patches_to_register_as_done, array_keys($this->patches_to_apply) + array_keys($performed_patches)); if (!empty($patches_to_register_as_done)) { $patches_list = 'Other patches found (' . count($patches_to_register_as_done) . '): ' . PHP_EOL; foreach ($patches_to_register_as_done as $patch_filename) { $patches_list .= $patch_filename; $patch_classname = Helper::getClassnameFromFilepath($patch_filename); /** @var AbstractSqlUpdate $patch */ $patch = new $patch_classname(); if ($patch->getType() == SqlUpdateInterface::TYPE_LARGE) { $patches_list .= " [01;31m[Large][0m"; } $patches_list .= PHP_EOL; } $this->logger->log($patches_list); if (count($patches_to_register_as_done) > 1) { $choice = $this->local_shell->inputPrompt('[a]pply, [r]egister as done, [p]ick, [i]gnore (a/r/p/I): ', 'i', false, array('a', 'r', 'p', 'i')); } else { $choice = $this->local_shell->inputPrompt('[a]pply, [r]egister as done, [i]gnore (a/r/I): ', 'i', false, array('a', 'r', 'i')); } if ('a' == $choice) { $this->patches_to_apply += $patches_to_register_as_done; } elseif ('r' == $choice) { $this->patches_to_register_as_done += $patches_to_register_as_done; } elseif ('p' == $choice) { list($picked_apply, $picked_register) = $this->pickPatches($patches_to_register_as_done, array('a', 'r', 'i'), 'i'); $this->patches_to_apply += $picked_apply; $this->patches_to_register_as_done += $picked_register; } } } if (empty($this->patches_to_apply) && empty($this->patches_to_register_as_done) && empty($this->patches_to_revert)) { return; } $this->getDatabaseLogin(); }
/** * @param array $files The SQL update files that should be executed */ public function setUpdateFiles($files) { $this->sql_patch_objects = DatabaseHelper::checkFiles($this->rootpath, $files, $this->patchOptions); }
/** * @param array $files The SQL update files that should be executed */ public function setUpdateFiles($files) { $this->sql_patch_objects = DatabaseHelper::checkFiles($this->rootpath, $files, array('charset' => $this->charset)); }