1<?php 2/* 3 * Copyright 2016 Google Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18namespace Google\Auth\Cache; 19 20use Psr\Cache\CacheItemInterface; 21use Psr\Cache\CacheItemPoolInterface; 22 23/** 24 * Simple in-memory cache implementation. 25 */ 26final class MemoryCacheItemPool implements CacheItemPoolInterface 27{ 28 /** 29 * @var CacheItemInterface[] 30 */ 31 private $items; 32 33 /** 34 * @var CacheItemInterface[] 35 */ 36 private $deferredItems; 37 38 /** 39 * {@inheritdoc} 40 * 41 * @return CacheItemInterface The corresponding Cache Item. 42 */ 43 public function getItem($key): CacheItemInterface 44 { 45 return current($this->getItems([$key])); // @phpstan-ignore-line 46 } 47 48 /** 49 * {@inheritdoc} 50 * 51 * @return iterable<CacheItemInterface> 52 * A traversable collection of Cache Items keyed by the cache keys of 53 * each item. A Cache item will be returned for each key, even if that 54 * key is not found. However, if no keys are specified then an empty 55 * traversable MUST be returned instead. 56 */ 57 public function getItems(array $keys = []): iterable 58 { 59 $items = []; 60 $itemClass = \PHP_VERSION_ID >= 80000 ? TypedItem::class : Item::class; 61 foreach ($keys as $key) { 62 $items[$key] = $this->hasItem($key) ? clone $this->items[$key] : new $itemClass($key); 63 } 64 65 return $items; 66 } 67 68 /** 69 * {@inheritdoc} 70 * 71 * @return bool 72 * True if item exists in the cache, false otherwise. 73 */ 74 public function hasItem($key): bool 75 { 76 $this->isValidKey($key); 77 78 return isset($this->items[$key]) && $this->items[$key]->isHit(); 79 } 80 81 /** 82 * {@inheritdoc} 83 * 84 * @return bool 85 * True if the pool was successfully cleared. False if there was an error. 86 */ 87 public function clear(): bool 88 { 89 $this->items = []; 90 $this->deferredItems = []; 91 92 return true; 93 } 94 95 /** 96 * {@inheritdoc} 97 * 98 * @return bool 99 * True if the item was successfully removed. False if there was an error. 100 */ 101 public function deleteItem($key): bool 102 { 103 return $this->deleteItems([$key]); 104 } 105 106 /** 107 * {@inheritdoc} 108 * 109 * @return bool 110 * True if the items were successfully removed. False if there was an error. 111 */ 112 public function deleteItems(array $keys): bool 113 { 114 array_walk($keys, [$this, 'isValidKey']); 115 116 foreach ($keys as $key) { 117 unset($this->items[$key]); 118 } 119 120 return true; 121 } 122 123 /** 124 * {@inheritdoc} 125 * 126 * @return bool 127 * True if the item was successfully persisted. False if there was an error. 128 */ 129 public function save(CacheItemInterface $item): bool 130 { 131 $this->items[$item->getKey()] = $item; 132 133 return true; 134 } 135 136 /** 137 * {@inheritdoc} 138 * 139 * @return bool 140 * False if the item could not be queued or if a commit was attempted and failed. True otherwise. 141 */ 142 public function saveDeferred(CacheItemInterface $item): bool 143 { 144 $this->deferredItems[$item->getKey()] = $item; 145 146 return true; 147 } 148 149 /** 150 * {@inheritdoc} 151 * 152 * @return bool 153 * True if all not-yet-saved items were successfully saved or there were none. False otherwise. 154 */ 155 public function commit(): bool 156 { 157 foreach ($this->deferredItems as $item) { 158 $this->save($item); 159 } 160 161 $this->deferredItems = []; 162 163 return true; 164 } 165 166 /** 167 * Determines if the provided key is valid. 168 * 169 * @param string $key 170 * @return bool 171 * @throws InvalidArgumentException 172 */ 173 private function isValidKey($key) 174 { 175 $invalidCharacters = '{}()/\\\\@:'; 176 177 if (!is_string($key) || preg_match("#[$invalidCharacters]#", $key)) { 178 throw new InvalidArgumentException('The provided key is not valid: ' . var_export($key, true)); 179 } 180 181 return true; 182 } 183} 184