bfb57b4e1e
Factor out the duplicated sync logic from syncAddresses(), syncPhones(), and syncEmails() into a single generic syncSubEntities() method that accepts callables for fetch/update/create/delete operations. Each specialized sync method is now a thin ~10-line wrapper. (Closes #204)
1.9 KiB
1.9 KiB
Issue #204: Duplicate Sub-Entity Sync Methods
Problem
MemberService contains three nearly identical methods for syncing sub-entities:
syncAddresses()syncPhones()syncEmails()
They all follow the same pattern:
- Fetch existing entities
- Index by ID
- Update kept IDs, create new ones
- Delete removed IDs
This violates DRY (Don't Repeat Yourself) and makes maintenance harder.
Current Code
private function syncAddresses(int $memberId, array $incoming): void {
$existing = $this->addressMapper->findByMemberId($memberId);
$existingById = [];
foreach ($existing as $addr) {
$existingById[$addr->getId()] = $addr;
}
$keptIds = [];
foreach ($incoming as $item) {
$id = isset($item['id']) ? (int)$item['id'] : 0;
if ($id > 0 && isset($existingById[$id])) {
$this->updateAddress($id, $item);
$keptIds[$id] = true;
} else {
$this->addAddress($memberId, $item);
}
}
foreach ($existingById as $id => $addr) {
if (!isset($keptIds[$id])) {
$this->deleteAddress($id);
}
}
}
// syncPhones() and syncEmails() are identical except for Address → Phone/Email
Solution
Extract the common sync logic into a single private generic method that accepts callables for the mapper-specific operations. Each of the three sync methods becomes a thin 10-line wrapper calling the generic method.
Tasks
- Extract common sync logic into
syncSubEntities()private generic method - Refactor
syncAddresses(),syncPhones(),syncEmails()to use the new pattern - Ensure identical behavior is preserved (all existing tests must pass)
- Run
make test— all must pass - Commit, push, create PR via tea, merge it
- Move plan file from
.plans/open/to.plans/done/ - Check out main again
Labels
- refactoring
- backend
- priority:medium