Skip to content

Conversation

@Sperling-0
Copy link
Contributor

@moiikana moiikana requested review from Abban, gbirke and moiikana March 20, 2025 09:09
@Sperling-0 Sperling-0 force-pushed the building-number branch 18 times, most recently from 62af393 to 7a377c3 Compare March 20, 2025 20:37
Copy link
Member

@Abban Abban left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're getting there. I've left a couple of suggestions, and don't forget to add tests for every class you changed. We especially want to test that the data makes it through the use cases and converters intact.

/**
* @deprecated Use fromStreetNameAndHouseNumber() instead.
*/
public function __construct( string $streetAddress, string $postalCode, string $city, string $countryCode ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should make the constructor private, as it's not deprecated. Then look for everywhere it's used and replace it with PostalAddress::fromLegacyStreetName()

return [];
}

/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add a method like this to the DonorFieldMapper:

private function getStreetAddress( Address $address ): string {
    if ( $address->getStreetAddress() != '' ) {
       return $address->getStreetAddress();
    }
    return "{$address->getStreetName()} {$address->getHouseNumber()}";
}

Then your return array would be:

return [
	'strasse' => $this->getStreetAddress( $address ),
	'plz' => $address->getPostalCode(),
	'ort' => $address->getCity(),
	'country' => $address->getCountryCode(),
];

Copy link
Member

@gbirke gbirke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR needs to be improved in several ways (most of them already
outlined in the ticket):

  1. We could have a quick discussion on where to store the new fields:
    • in the "data blob", to be consistent, avoid the need for a migration and have an easy backwards compatibility?
    • In the donation table. This would distribute the address data across the table and the data blob. It would also make it query-able and could be seen as a good step towards getting rid of the data blob.
    • In a separate table. I've outlined extracting the donor data in a separate table in https://phabricator.wikimedia.org/T203679 But this would be a large refactoring that's probably out of scope for this ticket. It will remove a lot of code in the long run, but affects several code parts (donation confirmation, donor address update, analysis and reports in FOC). The perspective of this refactoring should inform our choice of going with the data blob or the columns - what will be easier to refactor in the future?
  2. The changes need to be backwards-compatible: setting streetName and houseNumber should both update the streetAddress (strasse) field in the data blob, otherwise we'll run into trouble when exporting the data and showing it in the FOC.
  3. Let's make it more explicit what type of address we have. I'd recommend having two classes, PostalAddress and LegacyPostalAddress (or, if you run into typing trouble
    with that, an abstract AbstractPostalAddress that has two children). The classes can then have their own implementation for getting the legacy streetAddress field and you don't need the two constructors. We also reduce the cyclomatic complexity of the code (fewer if statements), because the only place where we have to check is DonorFactory: If the Doctrine entity (or its data blob) has a non-empty streetName then create a PostalAddress, otherwise create a LegacyPostalAddress
  4. If we're going with database columns, don't make them nullable (both in DB definition and property definition). A nullable value forces us to do null checks (more code, more potential complaints from PHPStan when the null check is missing) but for these fields an empty string check is fully sufficient.
  5. If we choose to store the data in table columns (see 1), we must add code to LegacyToDomainConverter and DomainToLegacyConverter that fills the fields correctly (and also clears the field for scrubbed donors, please write a test case for that, e.g. testGivenDonationWithAddressData_updatingDonationAsScrubbedWillClearAddressColumn). DonorFieldMapper is only for the
    data blob.

if ( $address->getStreetAddress() != '' ) {
return $address->getStreetAddress();
}
return "{$address->getStreetName()} {$address->getHouseNumber()}";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will return a non-empty string for anonymous and scrubbed addresses. I know that there is an if-statement that guards against this, but if we ever unwittingly call getStreetAddress from another place, we're opening ourselves up for unexpected data.


private static function createPhysicalAddress( DataReaderWithDefault $data ): PostalAddress {
return new PostalAddress(
return PostalAddress::fromLegacyStreetName(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will always produce a legacy postal address, even when the underlying data is non-legacy. See my review comment for recommendations.

@Sperling-0
Copy link
Contributor Author

Note

This PR will be worked on later.
https://phabricator.wikimedia.org/T369158

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants