Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
en:entwickler:changelog_implementation [2025/02/16 11:30] kainhoferen:entwickler:changelog_implementation [2025/03/21 08:55] (current) kainhofer
Line 5: Line 5:
 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}}
  
  
Line 179: Line 179:
     * The raw database table name is translated into a nice label by the ''static ChangelogService::getTableLabel(string $table)'' method     * The raw database table name is translated into a nice label by the ''static ChangelogService::getTableLabel(string $table)'' method
     * Object name: The display name is already stored in the adm_log_changes table. The changelog page first tries to translate it using ''Language::translateIfTranslationStrId''. It then tries to create a link to the object using the ''%%static ChangelogService::createLink(string $text, string $module, int|string $id, string $uuid = '')%%'' method. If the 'log_record_linkid' is set, then this ID is used in the link rather than the original record ID/UUID.     * Object name: The display name is already stored in the adm_log_changes table. The changelog page first tries to translate it using ''Language::translateIfTranslationStrId''. It then tries to create a link to the object using the ''%%static ChangelogService::createLink(string $text, string $module, int|string $id, string $uuid = '')%%'' method. If the 'log_record_linkid' is set, then this ID is used in the link rather than the original record ID/UUID.
-    * If a record has a related record stored in the changelog, the same is done for the related record. By default, the related record uses the same object type. If this is not desired (e.g. a File has its parent folder as its related object), then one has to change the ''changelog.php'' to modify the object type for the related object.+    * If a record has a related record stored in the changelog, the same is done for the related record. By default, the related record uses the same object type. If this is not desired (e.g. a File has its parent folder as its related object), then one has to change the ''static ChangelogService::getRelatedTable'' method  to modify the object type for the related object.
     * To translate the raw database column names (or field names in general) into nice labels, and define data types for it values, the ''static ChangelogService::getFieldTranslations()'' method defines a mapping table.     * To translate the raw database column names (or field names in general) into nice labels, and define data types for it values, the ''static ChangelogService::getFieldTranslations()'' method defines a mapping table.
       <code php>       <code php>
Line 270: Line 270:
 ====== Part C: Steps to Extend the Admidio Core with a New Module / Plugin ====== ====== Part C: Steps to Extend the Admidio Core with a New Module / Plugin ======
  
-At the example of the Forum module's tables (adm_forum_posts and adm_forum_topics), these are the steps to implement full support. Basic changelog support already works out of the box with no required code changes (enabled with the ''changelog_table_others'' preference flag for all unknown or third-party database table).+At the example of the Forum module's tables (adm_forum_posts and adm_forum_topics), these are the steps to implement full support. Basic changelog support already works out of the box with no required code changes (enabled with the ''changelog_table_others'' preference flag for all unknown or third-party database table). All changes described here are only required to get a nicer changelog view with links and easy-to-understand labels. 
 + 
 +The example of the forum module is taken directly from the admidio code tree ([[https://github.com/Admidio/admidio/commit/ff61d0a0029be89e88a4bccdfbb227b9af612efc|commit ff61d0a on github]])
  
   - **A: Preparation / General setup for forum logging**   - **A: Preparation / General setup for forum logging**
Line 371: Line 373:
 case 'forum_topics: case 'forum_topics:
     return 'forum_posts';     return 'forum_posts';
-} 
 </code> </code>
     - **Object name in changelog headline**: Create empty Topic and Post objects for given tables name 'forum_topics' and 'forum_posts' (file ''src/Changelog/Service/ChangelogService.php'')     - **Object name in changelog headline**: Create empty Topic and Post objects for given tables name 'forum_topics' and 'forum_posts' (file ''src/Changelog/Service/ChangelogService.php'')
Line 393: Line 394:
 ====== 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 itsels is done directly in the Admidio core code+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 moduleswhich is not directly available for change to third-party extension developers. 
  
-======= TODO ======= 
  
-  * How to add new tables/objects to the logging (core development or third-party) +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>/** 
-    * General setup for basic logging + * Register a callback function or value for the changelog functionality. If the callback is a value (string, array, etc.), it will  
-    * Translating DB name and columns (display in changelog+ * 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 
-    * Adding links to the objects + * function returns a null or empty  value, the next callback or the default processing of the ChangelogService method will proceed. 
-    * adding data types to DB columns + * @param string $function The method of the ChangelogService class that should be customized. One of  
-    * Ignoring certain tablescolumns or changes +     'getTableLabel', 'getTableLabelArray', 'getObjectForTable', 'getFieldTranslations', 'createLink',  
-    * Logging a change as something different (e.gcreation of a membership records as a modification of user) +     'formatValue', 'getRelatedTable', 'getPermittedTables' 
-    * Displaying the changelog button + * @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::encodeUrlADMIDIO_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>
  • en/entwickler/changelog_implementation.1739701806.txt.gz
  • Last modified: 2025/02/16 11:30
  • by kainhofer