Feature: Profile updates from user data announce themselves 

Description 

AbstractProfileFactory::updateProfileForUser() — the path behind the academic:updateprofiles command — persisted its changes without dispatching AfterProfileUpdateEvent ; only the profile creation did. A profile updated from its frontend user record therefore changed without its translations being synchronised and without its slug being regenerated, while the same change made through the frontend editing plugins did both.

The update path now dispatches the event per profile the update ran through, after persistAll() , carrying the persisted default language profile — the same contract as the creation path and the frontend editing flow, which both announce a profile even when every value already matched.

The skip_sync flag gates the whole update per profile now: a profile carrying it is neither data-updated nor announced. Previously the flag was only evaluated per frontend user, so a user carrying a second, synchronisable profile had the skip_sync profile updated through that side door.

Impact 

An academic:updateprofiles run now triggers the registered listeners for every synchronisable profile of the selected users. With academic_persons_edit installed that means: profile slugs are regenerated, and — with profile.allowedLanguages configured — the profile translations are created or synchronised. Installations relying on the command not touching slugs or translations should review their listener configuration before updating.

Affected Installations 

Every installation using the academic:updateprofiles command, and any installation with a frontend user connected to several profiles of which some carry skip_sync .