HierarchicalCachePoolTrait.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. /*
  3. * This file is part of php-cache organization.
  4. *
  5. * (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace Cache\Hierarchy;
  11. use Cache\Adapter\Common\AbstractCachePool;
  12. /**
  13. * @author Tobias Nyholm <tobias.nyholm@gmail.com>
  14. */
  15. trait HierarchicalCachePoolTrait
  16. {
  17. /**
  18. * A temporary cache for keys.
  19. *
  20. * @type array
  21. */
  22. private $keyCache = [];
  23. /**
  24. * Get a value from the storage.
  25. *
  26. * @param string $name
  27. *
  28. * @return mixed
  29. */
  30. abstract public function getDirectValue($name);
  31. /**
  32. * Get a key to use with the hierarchy. If the key does not start with HierarchicalPoolInterface::SEPARATOR
  33. * this will return an unalterered key. This function supports a tagged key. Ie "foo:bar".
  34. *
  35. * @param string $key The original key
  36. * @param string &$pathKey A cache key for the path. If this key is changed everything beyond that path is changed.
  37. *
  38. * @return string|array
  39. */
  40. protected function getHierarchyKey($key, &$pathKey = null)
  41. {
  42. if (!$this->isHierarchyKey($key)) {
  43. return $key;
  44. }
  45. $key = $this->explodeKey($key);
  46. $keyString = '';
  47. // The comments below is for a $key = ["foo!tagHash", "bar!tagHash"]
  48. foreach ($key as $name) {
  49. // 1) $keyString = "foo!tagHash"
  50. // 2) $keyString = "foo!tagHash![foo_index]!bar!tagHash"
  51. $keyString .= $name;
  52. $pathKey = sha1('path'.AbstractCachePool::SEPARATOR_TAG.$keyString);
  53. if (isset($this->keyCache[$pathKey])) {
  54. $index = $this->keyCache[$pathKey];
  55. } else {
  56. $index = $this->getDirectValue($pathKey);
  57. $this->keyCache[$pathKey] = $index;
  58. }
  59. // 1) $keyString = "foo!tagHash![foo_index]!"
  60. // 2) $keyString = "foo!tagHash![foo_index]!bar!tagHash![bar_index]!"
  61. $keyString .= AbstractCachePool::SEPARATOR_TAG.$index.AbstractCachePool::SEPARATOR_TAG;
  62. }
  63. // Assert: $pathKey = "path!foo!tagHash![foo_index]!bar!tagHash"
  64. // Assert: $keyString = "foo!tagHash![foo_index]!bar!tagHash![bar_index]!"
  65. // Make sure we do not get awfully long (>250 chars) keys
  66. return sha1($keyString);
  67. }
  68. /**
  69. * Clear the cache for the keys.
  70. */
  71. protected function clearHierarchyKeyCache()
  72. {
  73. $this->keyCache = [];
  74. }
  75. /**
  76. * A hierarchy key MUST begin with the separator.
  77. *
  78. * @param string $key
  79. *
  80. * @return bool
  81. */
  82. private function isHierarchyKey($key)
  83. {
  84. return substr($key, 0, 1) === HierarchicalPoolInterface::HIERARCHY_SEPARATOR;
  85. }
  86. /**
  87. * This will take a hierarchy key ("|foo|bar") with tags ("|foo|bar!tagHash") and return an array with
  88. * each level in the hierarchy appended with the tags. ["foo!tagHash", "bar!tagHash"].
  89. *
  90. * @param string $string
  91. *
  92. * @return array
  93. */
  94. private function explodeKey($string)
  95. {
  96. list($key, $tag) = explode(AbstractCachePool::SEPARATOR_TAG, $string.AbstractCachePool::SEPARATOR_TAG);
  97. if ($key === HierarchicalPoolInterface::HIERARCHY_SEPARATOR) {
  98. $parts = ['root'];
  99. } else {
  100. $parts = explode(HierarchicalPoolInterface::HIERARCHY_SEPARATOR, $key);
  101. // remove first element since it is always empty and replace it with 'root'
  102. $parts[0] = 'root';
  103. }
  104. return array_map(function ($level) use ($tag) {
  105. return $level.AbstractCachePool::SEPARATOR_TAG.$tag;
  106. }, $parts);
  107. }
  108. }