fix!: read timezone from config#186
Conversation
There was a problem hiding this comment.
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 extraContextparameter 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_runbut 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->readTableAPI. 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' => $timezoneor other strange things - (Not sure about this one) but is that
config.phpreally 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 thisconfig.phpvalue could be wrong / unused? - The only reliable way I see would be asking the SW5 backend itself (e.g. they executed
config.phpand 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
| ->format(Defaults::STORAGE_DATE_TIME_FORMAT); | ||
| } catch (\Throwable $exception) { | ||
| $this->loggingService->log( | ||
| MigrationLogBuilder::fromMigrationContext($this->migrationContext) |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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') { |
There was a problem hiding this comment.
would be good to make constants in TimezoneReader public and reuse here
Malte Janz (MalteJanz)
left a comment
There was a problem hiding this comment.
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.
| 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(); | ||
| } | ||
| } |
There was a problem hiding this comment.
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
|
|
||
| #[Package('fundamentals@after-sales')] | ||
| abstract class ShopwareConverter extends Converter | ||
| abstract class ShopwareConverter extends Converter implements ResetInterface |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
closes: shopware/shopware#14186