Both sides previous revision Previous revision Next revision | Previous revision |
en:entwickler:changelog_implementation [2025/02/16 11:47] – [Part C: Steps to Extend the Admidio Core with a New Module / Plugin] kainhofer | en:entwickler:changelog_implementation [2025/03/21 08:55] (current) – kainhofer |
---|
Starting with Admidio 5.0, all changes to objects (Users, Events, Groups/Roles, Weblinks, Albums, Folders/Files, ...) and settings that are saved in Admidio's database can be logged and the changes displayed in the Change History screen. Logging can be enabled per object type (=database table) in the preferences. Each object or list with changelogs enabled will display a changelog button to view it: | Starting with Admidio 5.0, all changes to objects (Users, Events, Groups/Roles, Weblinks, Albums, Folders/Files, ...) and settings that are saved in Admidio's database can be logged and the changes displayed in the Change History screen. Logging can be enabled per object type (=database table) in the preferences. Each object or list with changelogs enabled will display a changelog button to view it: |
| |
}{{:en:entwickler:changelog:changelog_view_overview.png?400|The new changelog view}}{{:en:entwickler:changelog:changelog_settings.png?400|Settings for the changelog}}{{:en:entwickler:changelog:changelog_button_preferences.png?200|View changelog button}} | {{:en:entwickler:changelog:changelog_view_overview.png?400|The new changelog view}}{{:en:entwickler:changelog:changelog_settings.png?400|Settings for the changelog}}{{:en:entwickler:changelog:changelog_button_preferences.png?200|View changelog button}} |
| |
| |
====== Part D: Additional Steps for Third-Party Extensions ====== | ====== Part D: Additional Steps for Third-Party Extensions ====== |
| |
Adding support for changelogs in third-party extensions, where modifying the core Admidio code is not possible, works similar to the above steps. Modifying the changelog entry creation is implemented inside the extension's Entity-derived database access classes, so this part is similar to core modules. Unfortunately, the adjustments to the changelog itself is done directly in the Admidio core code in the class ''ChangelogService'' and is currently not possible for third-party extensions. | Adding support for changelogs in third-party extensions, where modifying the core Admidio code is not possible, works similar to the above steps. Modifying the changelog entry creation is implemented inside the extension's Entity-derived database access classes, so this part is similar to core modules. However, the formatting in the Change history page view is implemented in the class ''ChangelogService'' for the core modules, which is not directly available for change to third-party extension developers. |
| |
However, the ChanglogService class is structured in a way that for each method, one could either | |
* add a method to append mappings directly to the arrays used in the static method of the Changelog class, or | |
* add a list of callback functions that are called in turn, when the default code does not handle a certain table/column/object. One would need to add a method to register such a callback function for each of the static methods. | |
| |
This generalization of the ChangelogService class is not yet done, and also not currently planned. However, anyone interested can start working on it and submit patches to the admidio project. | However, the ChanglogService class additionally provides a way to register mapping tables for table/column names or general callback functions for all the methods that need modifications as described above. The callback functions are registered with the method <code php>/** |
| * Register a callback function or value for the changelog functionality. If the callback is a value (string, array, etc.), it will |
| * be returned. If the callback is a function, it will be executed and if the return value is not empty, it will be returned. If the |
| * function returns a null or empty value, the next callback or the default processing of the ChangelogService method will proceed. |
| * @param string $function The method of the ChangelogService class that should be customized. One of |
| * 'getTableLabel', 'getTableLabelArray', 'getObjectForTable', 'getFieldTranslations', 'createLink', |
| * 'formatValue', 'getRelatedTable', 'getPermittedTables' |
| * @param string $moduleOrKey The module or type that should be customized. If empty, the callback will be |
| * executed for all values and it will be used if it evaluates to a non-empty value. |
| * @param mixed $callback The callback function or value. A value will be returned unchanged, a function will |
| be executed (arguments are identical to the ChangelogService's methods) |
| */ |
| static ChangelogService::registerCallback(string $function, string $moduleOrKey, mixed $callback)</code> |
| |
| Using these callback mechanisms, the forum changelog described above could also be implemented with the following code. It should be executed somewhere during php startup when the third-party module is loaded, and before either a changelog page can be displayed or before any of the third-party extension's database records are modified (i.e. before the extension writes data to the database). |
| |
| <code php> |
| |
| ## Translation of database tables |
| ChangelogService::registerCallback('getTableLabelArray', 'forum_topics', 'SYS_FORUM_TOPIC'); |
| ChangelogService::registerCallback('getTableLabelArray', 'forum_posts', 'SYS_FORUM_POST'); |
| |
| ## Translations and type definitions of database columns |
| ChangelogService::registerCallback('getFieldTranslations', '', [ |
| 'fot_cat_id' => array('name' => 'SYS_CATEGORY', 'type' => 'CATEGORY'), |
| 'fot_fop_id_first_post' => array('name' => 'SYS_FORUM_POST', 'type' => 'POST'), |
| 'fot_title' => 'SYS_TITLE', |
| 'fop_text' => 'SYS_TEXT', |
| 'fop_fot_id' => array('name' => 'SYS_FORUM_TOPIC', 'type' => 'TOPIC') |
| ]); |
| |
| ## Formatting of new database column types (in many cases not needed) |
| ChangelogService::registerCallback('formatValue', 'TOPIC', function($value, $type, $entries = []) { |
| global $gDb; |
| if (empty($value)) return ''; |
| $obj = new Topic($gDb, $value??0); |
| return ChangelogService::createLink($obj->readableName(), 'forum_topics', |
| $obj->getValue('fot_id'), $obj->getValue('fot_uuid')); |
| }); |
| ChangelogService::registerCallback('formatValue', 'POST', function($value, $type, $entries = []) { |
| global $gDb; |
| if (empty($value)) return ''; |
| $obj = new POST($gDb, $value??0); |
| return ChangelogService::createLink($obj->readableName(), 'forum_posts', |
| $obj->getValue('fop_id'), $obj->getValue('fop_uuid')); |
| }); |
| |
| ## Create HTML links to the object's list view and edit pages |
| ChangelogService::registerCallback('createLink', 'forum_topics', function(string $text, string $module, int|string $id, string $uuid = '') { |
| return SecurityUtils::encodeUrl( ADMIDIO_URL.FOLDER_MODULES.'/forum.php', |
| array('mode' => 'topic', 'topic_uuid' => $uuid)); |
| }); |
| ChangelogService::registerCallback('createLink', 'forum_posts', function(string $text, string $module, int|string $id, string $uuid = '') { |
| return SecurityUtils::encodeUrl( ADMIDIO_URL.FOLDER_MODULES.'/forum.php', |
| array('mode' => 'post_edit', 'post_uuid' => $uuid)); |
| }); |
| |
| ## Object types of related objects (if object relations are used at all!) |
| ChangelogService::registerCallback('getRelatedTable', 'forum_topics', 'forum_posts'); |
| ChangelogService::registerCallback('getRelatedTable', 'forum_posts', 'forum_topics'); |
| |
| |
| ## Create Entity-derived objects to create headlines with proper object names |
| ChangelogService::registerCallback('getObjectForTable', 'forum_topics', function() {global $gDb; return new Topic($gDb);}); |
| ChangelogService::registerCallback('getObjectForTable', 'forum_posts', function() {global $gDb; return new Post($gDb);}); |
| |
| ## Enable per-user detection of access permissions to the tables (based on user's role permission); Admin is always allowed |
| ChangelogService::registerCallback('getPermittedTables', '', function(User $user) { |
| if ($user->administrateForum()) |
| return ['forum_topics', 'forum_posts']; |
| }); |
| </code> |