66 lines
1.9 KiB
Markdown
66 lines
1.9 KiB
Markdown
# 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:
|
|
1. Fetch existing entities
|
|
2. Index by ID
|
|
3. Update kept IDs, create new ones
|
|
4. Delete removed IDs
|
|
|
|
This violates DRY (Don't Repeat Yourself) and makes maintenance harder.
|
|
|
|
## Current Code
|
|
|
|
```php
|
|
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
|