Skip to content

fix!: read timezone from config#186

Open
Dennis Garding (DennisGarding) wants to merge 11 commits into
trunkfrom
14186/time-zone-diff
Open

fix!: read timezone from config#186
Dennis Garding (DennisGarding) wants to merge 11 commits into
trunkfrom
14186/time-zone-diff

Conversation

@DennisGarding
Copy link
Copy Markdown
Contributor

Comment thread src/Profile/Shopware/Premapping/TimezoneReader.php Outdated
@DennisGarding Dennis Garding (DennisGarding) marked this pull request as draft May 4, 2026 14:09
Comment thread src/Profile/Shopware/Gateway/Local/Reader/TimezoneReader.php Outdated
Comment thread src/Profile/Shopware/Premapping/TimezoneReader.php Outdated
Comment thread src/Profile/Shopware/Converter/ShopwareConverter.php Outdated
Comment thread src/Profile/Shopware/Gateway/Local/Reader/EnvironmentReader.php Outdated
Comment thread src/Profile/Shopware/Gateway/Local/Reader/EnvironmentReader.php Outdated
@DennisGarding Dennis Garding (DennisGarding) marked this pull request as ready for review May 8, 2026 06:13
Comment thread src/Profile/Shopware/Converter/ShopwareConverter.php
Comment thread src/Profile/Shopware/Gateway/Api/Reader/EnvironmentReader.php Outdated
Comment thread tests/acceptance/fixtures/shopware5-source/config.php Outdated
Comment thread tests/acceptance/tests/MigrationTest.spec.ts Outdated
Comment thread src/Profile/Shopware/Converter/ShopwareConverter.php Outdated
Comment thread src/Profile/Shopware/Converter/ShopwareConverter.php Outdated
Comment thread src/Profile/Shopware/Gateway/Local/Reader/EnvironmentReader.php Outdated
@MalteJanz Malte Janz (MalteJanz) self-requested a review May 8, 2026 08:32
Copy link
Copy Markdown
Contributor

@MalteJanz Malte Janz (MalteJanz) left a comment

Choose a reason for hiding this comment

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

The more I think about it, the more I think the extra effort for reading the SW5 configured timezone isn't worth it. Sorry for leading you down this EnvironmentReader path with my previous comment and our short talk.

What if we apply the simplest solution we could come up with here, just a few of my thoughts (feel free to explore a simpler approach on your own / deviate from this):

  • No reading (or guessing) from the source system at all
  • Premapping has a option for setting the "storage timezone" of the source system, which is like all other premappings put into the mapping table and can be used from there
  • possible choices would be all valid timezones
  • we could think about defaulting / pre-selecting "UTC", if that works for the majority of cases and otherwise the user can still adjust it and migrate again
  • I still like your approach of using Converter->convertValue(..., TYPE_DATETIME) to do the correct conversion automatically, but I would prefer if we could get rid of the extra Context parameter there and initialize the internal used source timezone differently from the mapping

My reasoning behind this:

  • Doing a full "read environment" call is expensive and should not really be necessary. I previously thought we might store the values of that somewhere in the DB but I was wrong about that (turns out we store it on the swag_migration_run but at the premapping stage we don't have a run yet)
  • The other premapping readers also sometimes read from the source system, but they only use a dedicated $gateway->readTable API. In our case we don't need DB data but rather configuration values stored as a file. Introducing extra APIs for that seems not worth the effort
  • Reading the SW5 config from a PHP file is error prone, e.g. they could also store the timezone in a variable and use that in multiple places 'timezone' => $timezone or other strange things
  • (Not sure about this one) but is that config.php really the single source of truth for this configuration in SW5? Is it not possible to override / provide config values via environment variables or other ways, where this config.php value could be wrong / unused?
  • The only reliable way I see would be asking the SW5 backend itself (e.g. they executed config.php and can tell what value is "active"), but that wouldn't work for our local gateway and doesn't seem worth the effort just for giving the user a little more convenience

Comment thread src/DependencyInjection/shopware.php Outdated
Comment thread src/Profile/Shopware/Converter/ShopwareConverter.php Outdated
Comment thread src/Profile/Shopware/Converter/ShopwareConverter.php Outdated
Comment thread src/Profile/Shopware/Gateway/Api/Reader/EnvironmentReader.php Outdated
Comment thread src/Migration/EnvironmentInformation.php Outdated
Comment thread src/Profile/Shopware/Gateway/Local/Reader/EnvironmentReader.php Outdated
->format(Defaults::STORAGE_DATE_TIME_FORMAT);
} catch (\Throwable $exception) {
$this->loggingService->log(
MigrationLogBuilder::fromMigrationContext($this->migrationContext)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

would be good to add at least entityName here, so its possible to identify

use SwagMigrationAssistant\Migration\Logging\Log\Builder\AbstractMigrationLogEntry;

#[Package('fundamentals@after-sales')]
readonly class ConvertDateTimeFailedLog extends AbstractMigrationLogEntry
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would not add a new Log for this. In the end it can simply be a ConvertEntityFailedLog or RunExceptionLog

$timezone = null;
$premapping = $this->migrationContext->getConnection()->getPremapping();
foreach ($premapping ?? [] as $item) {
if ($item->getEntity() !== 'source_timezone') {
Copy link
Copy Markdown
Member

@larskemper Lars Kemper (larskemper) May 12, 2026

Choose a reason for hiding this comment

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

would be good to make constants in TimezoneReader public and reuse here

Copy link
Copy Markdown
Contributor

@MalteJanz Malte Janz (MalteJanz) left a comment

Choose a reason for hiding this comment

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

Because there aren't any comments / reactions to my previous comments (other than that they are resolved) and there is no meaningful PR description I have no clue what your current goal for a solution is. Looks like you still want to read the source system timezone?

Nevertheless the current implementation still has lots of issues related to that and also didn't follow my suggestion to not read from the source system to keep it simple. Please provide proper solutions to these issues or refactor to not read from the source system.

Comment on lines +240 to +258
private function getTimezoneFromPremapping(): ?string
{
$runId = $this->migrationContext->getRunUuid();
if (\array_key_exists($runId, $this->timezoneCache)) {
return $this->timezoneCache[$runId];
}

$timezone = null;
$premapping = $this->migrationContext->getConnection()->getPremapping();
foreach ($premapping ?? [] as $item) {
if ($item->getEntity() !== 'source_timezone') {
continue;
}

foreach ($item->getMapping() as $mapping) {
if ($mapping->getSourceId() === 'timezone') {
$timezone = $mapping->getDestinationUuid() === '' ? null : $mapping->getDestinationUuid();
}
}
Copy link
Copy Markdown
Contributor

@MalteJanz Malte Janz (MalteJanz) May 12, 2026

Choose a reason for hiding this comment

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

This is not how we read the submitted premapping in our converters, see our documentation on that here:
https://developer.shopware.com/docs/products/extensions/migration-assistant/concept/premapping.html

You just need to do a mapping lookup instead, e.g.:

$mapping = $this->mappingService->getMapping(
            $this->connectionId,
            TimezoneReader::getMappingName(),
            TimezoneReader::SOURCE_ID,
            $this->context,
        );

*You likely need to use getValue in this case though, because you don't want to look up a UUID, but instead just a string

public function getValue(string $connectionId, string $entityName, string $oldIdentifier, Context $context): ?string


#[Package('fundamentals@after-sales')]
abstract class ShopwareConverter extends Converter
abstract class ShopwareConverter extends Converter implements ResetInterface
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Where are all the child classes tagged with kernel.reset now? Otherwise just implementing this Interface is useless if its never called.

You might want to extract that datetime timezone conversion logic into its own service though, that way its stays independent of the ShopwareConverter and could potentially also be used by other profile converters such as Magento 🤷

return null;
}

$timezoneResult = $this->timezoneReader->read($migrationContext);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You can't just use the ApiTimezoneReader here, you need to go through the GatewayRegistry to get the correct gateway for the active connection and the use that to talk to the source system, otherwise this might just crash for connections with local gateway. Just take a look at our existing Premapping readers or our documentation about creating one:
https://developer.shopware.com/docs/products/extensions/migration-assistant/guides/decorating-a-shopware-migration-assistant-converter.html#creating-a-premapping-reader

But as I already said in my last code review, I don't think its worth the effort to read from the source system if that isn't even guaranteed to be reliable. Then its better to just let the user choose and maybe default to UTC if that's commonly set on SW5 by default?


$sourceTimezone = $this->readSourceTimezone($migrationContext);

$description = $sourceTimezone ?? 'No source time zone';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How does this description make sense? It should always say Source system time zone, not Europe/Berlin and then you have to choose Europe/Berlin as well 😕 ?

use SwagMigrationAssistant\Migration\MigrationContextInterface;

#[Package('after-sales')]
class TimezoneReader extends ApiReader
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If you really want to do this reading from the source system, where is the equivalent local gateway reader? Also the concept of these Readers are for reading data that is then converted, and are not really for fetching premapping data. For that all other PremappingReaders are using the GatewayInterface->readTable method.

I would again strongly recommend not to fetch the timezone from the source system, unless you find a clean solution that is guaranteed to work and always provides the correct source system timezone for both API and local gateways

{
public function supports(MigrationContextInterface $migrationContext): bool
{
return false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Dead code? Directly using this Reader from dependency injection is an anti-pattern and it should only be retrieved from the corresponding Registry, to support all possible gateways

@larskemper Lars Kemper (larskemper) changed the title fix: read timezone from config fix!: read timezone from config May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Timezone differences between source and target systems

4 participants