1: <?php
2: /**
3: * This class loops through a given list of storage drivers to search for a
4: * cached value. This driver allows for use of caching backends on top of
5: * persistent backends.
6: *
7: * Copyright 2010-2012 Horde LLC (http://www.horde.org/)
8: *
9: * See the enclosed file COPYING for license information (LGPL). If you
10: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
11: *
12: * @author Michael Slusarz <slusarz@horde.org>
13: * @category Horde
14: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
15: * @package Cache
16: */
17: class Horde_Cache_Storage_Stack extends Horde_Cache_Storage_Base
18: {
19: /**
20: * Stack of cache drivers.
21: *
22: * @var string
23: */
24: protected $_stack = array();
25:
26: /**
27: * Constructor.
28: *
29: * @param array $params Parameters:
30: * <pre>
31: * 'stack' - (array) [REQUIRED] An array of storage instances to loop
32: * through, in order of priority. The last entry is considered
33: * the 'master' driver, for purposes of writes.
34: * </pre>
35: *
36: * @throws InvalidArgumentException
37: */
38: public function __construct(array $params = array())
39: {
40: if (!isset($params['stack'])) {
41: throw new InvalidArgumentException('Missing stack parameter.');
42: }
43: $this->_stack = $params['stack'];
44: unset($params['stack']);
45:
46: parent::__construct($params);
47: }
48:
49: /**
50: */
51: public function get($key, $lifetime = 0)
52: {
53: foreach ($this->_stack as $val) {
54: $result = $val->get($key, $lifetime);
55: if ($result !== false) {
56: return $result;
57: }
58: }
59:
60: return false;
61: }
62:
63: /**
64: */
65: public function set($key, $data, $lifetime = 0)
66: {
67: /* Do writes in *reverse* order - it is OK if a write to one of the
68: * non-master backends fails. */
69: $master = true;
70:
71: foreach (array_reverse($this->_stack) as $val) {
72: $result = $val->set($key, $data, $lifetime);
73: if ($result === false) {
74: if ($master) {
75: return;
76: }
77:
78: /* Attempt to invalidate cache if write failed. */
79: $val->expire($key);
80: }
81: $master = false;
82: }
83: }
84:
85: /**
86: */
87: public function exists($key, $lifetime = 0)
88: {
89: foreach ($this->_stack as $val) {
90: $result = $val->exists($key, $lifetime);
91: if ($result === true) {
92: break;
93: }
94: }
95:
96: return $result;
97: }
98:
99: /**
100: */
101: public function expire($key)
102: {
103: /* Only report success from master. */
104: $master = $success = true;
105:
106: foreach (array_reverse($this->_stack) as $val) {
107: $result = $val->expire($key);
108: if ($master && ($result === false)) {
109: $success = false;
110: }
111: $master = false;
112: }
113:
114: return $success;
115: }
116:
117: /**
118: */
119: public function clear()
120: {
121: /* Only report errors from master. */
122: $exception = null;
123: $master = true;
124:
125: foreach (array_reverse($this->_stack) as $val) {
126: try {
127: $val->clear();
128: } catch (Horde_Cache_Exception $e) {
129: if ($master) {
130: $exception = $e;
131: }
132: }
133: $master = false;
134: }
135:
136: if ($exception) {
137: throw $exception;
138: }
139: }
140:
141: }
142: