From c9a173efe541911767c4f6efb6604ebe626f572d Mon Sep 17 00:00:00 2001 From: Vvardenfell Date: Sun, 25 Jan 2015 17:25:12 +0100 Subject: [PATCH 1/2] Adjusted reset callbacks functionality The modification allows reset callbacks to be used in a similar fashion as migrations. When a reset callback is invoked, the execution will be logged and consecutive executions will be suppressed. The callbacks are limited to one unique class/method combination when invoked on a particular instance of a given class. --- core/coreroutes/reset.php | 69 +++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/core/coreroutes/reset.php b/core/coreroutes/reset.php index 2aa99d4..88a8e0b 100644 --- a/core/coreroutes/reset.php +++ b/core/coreroutes/reset.php @@ -22,6 +22,10 @@ * Resets the project. */ class CoreRoutes_Reset extends Module { + + // path of reset callback logfile, relative to PROJECT_PATH + const RESET_CALLBACK_LOG_FILE = '/config/log/reset_callback.log.xml'; + private static $callbacksOnAfterReset = array(); public function init() { @@ -31,8 +35,12 @@ public function init() { DB_Connection::get()->deleteTables(); // remove migrations log - $file = new IO_File(PROJECT_PATH.Core_MigrationsLoader::MIGRATION_LOG_FILE); - $file->delete(); + $migrationFile = new IO_File(PROJECT_PATH.Core_MigrationsLoader::MIGRATION_LOG_FILE); + $migrationFile->delete(); + + // remove reset callbacks log + $resetCallbacksFile = new IO_File(PROJECT_PATH.self::RESET_CALLBACK_LOG_FILE); + $resetCallbacksFile->delete(); // clear global cache $GLOBALS['cache']->clearAll(); @@ -46,10 +54,8 @@ public function init() { // rebuild database Core_MigrationsLoader::load(); - if (defined('CALLBACK_ONAFTERRESET')) - self::addCallbackOnAfterReset(CALLBACK_ONAFTERRESET); - foreach (self::$callbacksOnAfterReset as $callback) - call_user_func($callback); + // execute registered callbacks + self::executeCallbacksOnAfterReset(); Scriptlet::redirect(PROJECT_ROOTURI); } @@ -57,6 +63,55 @@ public function init() { public static function addCallbackOnAfterReset($callback) { self::$callbacksOnAfterReset[] = $callback; } + + /** + * Executes the callbacks registered by addCallbackOnAfterReset + * or defined by the constant CALLBACK_ONAFTERRESET. + * Execution is only performed if the callbacks haven't been called + * since the last reset. + * This method is intended to be used when there's a reason to execute + * these callbacks once, even when there's no complete reset being performed. + * One such reason is the initial setup and running newly added callbacks + * in development mode. + * Callbacks that differ only in the instance of a class and not in the method called + * will be treated as if they were the same. So if more than one instance of a class + * is used for a callback, each instance needs its unique member function to be executed. + */ + public static function executeCallbacksOnAfterReset() { + + if (defined('CALLBACK_ONAFTERRESET')) + self::addCallbackOnAfterReset(CALLBACK_ONAFTERRESET); + + if (file_exists(PROJECT_PATH.self::RESET_CALLBACK_LOG_FILE)) + $xml = simplexml_load_file(PROJECT_PATH.self::RESET_CALLBACK_LOG_FILE); + else { + $baseResetCallbackLog = ''; + $xml = new SimpleXMLElement($baseResetCallbackLog); + } + + foreach (self::$callbacksOnAfterReset as $callback) { + if (is_array($callback) && isset($callback[0]) && isset($callback[1])) { + // different objects of the same class will be treated as if they were the same + $callbackIdentifier = get_class($callback[0]).'->'.$callback[1]; + } else $callbackIdentifier = $callback; + + // execute reset callbacks if they haven't been before + $result = $xml->xpath(sprintf('/content/callback[@identifier=\'%s\']', $callbackIdentifier)); + if (empty($result)) { + $result = $xml->xpath('/content'); + $child = $result[0]->addChild('callback'); + $child->addAttribute('identifier', $callbackIdentifier); + call_user_func($callback); + } + } + // save reset callback logfile + $doc = new DOMDocument('1.0'); + $doc->preserveWhiteSpace = false; + $doc->loadXML($xml->asXML()); + $doc->formatOutput = true; + $doc->save(PROJECT_PATH.self::RESET_CALLBACK_LOG_FILE); + } + } -?> \ No newline at end of file +?> From 1149f738184056437270ee8a6184d9f6f21bc5eb Mon Sep 17 00:00:00 2001 From: Vvardenfell Date: Sun, 25 Jan 2015 17:30:28 +0100 Subject: [PATCH 2/2] Invoke reset callbacks in development mode The registered reset callbacks will be executed in development mode as required. This behaviour equals to that of the execution of migrations. The modification allows for an automatic initial setup without having to make a HTTP GET request to /rakuun/core/reset. --- app.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app.php b/app.php index 34371a4..4654189 100644 --- a/app.php +++ b/app.php @@ -142,9 +142,11 @@ public static function boot() { Router::get()->init(); if (Environment::getCurrentEnvironment() == Environment::DEVELOPMENT) { - // always check for changed migrations on development (except when resetting) - if (!(Router::get()->getCurrentModule() instanceof CoreRoutes_Reset)) + // always check for changed migrations and reset callbacks on development (except when resetting) + if (!(Router::get()->getCurrentModule() instanceof CoreRoutes_Reset)) { Core_MigrationsLoader::load(); + CoreRoutes_Reset::executeCallbacksOnAfterReset(); + } } Router::get()->runCurrentModule(); @@ -427,4 +429,4 @@ function backtrace() { Core_Dump::backtrace(); } -?> \ No newline at end of file +?>