Skip to content

Conversation

@akhumphrey
Copy link

No description provided.

@akhumphrey akhumphrey added the bug Something isn't working label Sep 13, 2023
@akhumphrey akhumphrey self-assigned this Sep 13, 2023

$elements = array_merge(
[SharedCacheHelper::ROUTING_NAMESPACE],
$tparams
Copy link
Author

Choose a reason for hiding this comment

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

This is the source of the problem - only the values in $tparams were being included in the cache key generation.

The result of this oversight meant that we'd get incorrect cache hits for multiple different instances of url_for(...). For example:

  • url_for('pack', ['id' => $order_id, 'confirmation' => 1, 'force' => 1])
  • url_for('pack', ['id' => $order_id, 'undigital-flyer' => 1, 'force' => 1])

Both of these calls to url_for() would result in different final routes being generated if we were not caching. However, according to the previous caching logic, the cache keys for both these routes (and any in a similar format) would look something like: pack/[order_id]/1/1.

Whichever route had been cached under that key first would be what got returned for all similarly-formatted routes for the next three months, which is obviously nonsense.

{
$elements = [
SharedCacheHelper::ROUTING_NAMESPACE,
$this->flattenArrayElements($elements),
Copy link
Author

Choose a reason for hiding this comment

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

This fixes the problem. By flattening (with recursion, if necessary) both the keys and values down into a single numerically-indexed array, the above examples no longer cause incorrect cache hits with one another.

$flattened[] = $key;

if (is_array($value)) {
$flattened[] = $this->flattenArrayElements($value);
Copy link
Author

Choose a reason for hiding this comment

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

This feels unlikely, but I wanted to add some degree of protection in just in case.

protected function flattenArrayElements(array $elements = []): array
{
$flattened = [];
ksort($elements);
Copy link
Author

Choose a reason for hiding this comment

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

This will make sure we only cache a route once, even if the route arguments are given in a different order in different places. For example:

  • url_for('pack', ['id' => $order_id, 'confirmation' => 1, 'force' => 1])
  • url_for('pack', ['id' => $order_id, 'force' => 1, 'confirmation' => 1])

These routes are fundamentally the same, and would result in the same output from the routing engine. To cache them separately because the arguments are provided in a different order would be foolish and wasteful.

* Recursive method to pack a key => value pair array down into a flat
* numerically-indexed array, with a consistent ordering of elements.
*/
protected function flattenArrayElements(array $elements = []): array
Copy link

Choose a reason for hiding this comment

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

Interesting. Should this method be in some sort of helper class?

Copy link
Author

Choose a reason for hiding this comment

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

Umm....it's a good question, but I don't know if there are any other use cases for that functionality to be shared with.

I would definitely like to see the functionality shifted to a more centralised location if we have need for sharing it, but I would generally stick things close to where they're needed until we have a good reason to move it really.

@akhumphrey akhumphrey requested a review from xaes117 September 19, 2023 08:22
@akhumphrey akhumphrey merged commit 7394837 into master Sep 19, 2023
@akhumphrey akhumphrey deleted the nto-520 branch September 19, 2023 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants