Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 904aa74

Browse filesBrowse files
committed
memcached cache adapter configurable with dsn/options
1 parent d6e8937 commit 904aa74
Copy full SHA for 904aa74

File tree

2 files changed

+407
-0
lines changed
Filter options

2 files changed

+407
-0
lines changed
+183Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache\Adapter;
13+
14+
use Symfony\Component\Cache\Exception\InvalidArgumentException;
15+
16+
/**
17+
* @author Rob Frawley 2nd <rmf@src.run>
18+
*/
19+
class MemcachedAdapter extends AbstractAdapter
20+
{
21+
private static $defaultClientServer = array(
22+
'host' => '127.0.0.1',
23+
'port' => 11211,
24+
'weight' => 100,
25+
);
26+
27+
private $client;
28+
29+
public static function isSupported()
30+
{
31+
return extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>=');
32+
}
33+
34+
public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0)
35+
{
36+
parent::__construct($namespace, $defaultLifetime);
37+
$this->client = $client;
38+
}
39+
40+
/**
41+
* Factory method to create adapter setup with configured \Memcache client instance.
42+
*
43+
* Valid DSN values include the following:
44+
* - memcached://localhost : Specifies only the host (defaults used for port and weight)
45+
* - memcached://example.com:1234 : Specifies host and port (defaults weight)
46+
* - memcached://example.com:1234?weight=50 : Specifies host, port, and weight (no defaults used)
47+
*
48+
* Options are expected to be passed as an associative array with indexes of the option type with corresponding
49+
* values as the option assignment. Valid options include any \Memcached constants (either as their resolved value
50+
* or as their relative constant name string). Reference the PHP manual for available option values:
51+
* - http://php.net/manual/en/memcached.constants.php
52+
*
53+
* @param string|null $dsn
54+
* @param array $opts
55+
* @param string|null $persistentId
56+
*
57+
* @return MemcachedAdapter
58+
*/
59+
public static function create($dsn = null, array $opts = array(), $persistentId = null)
60+
{
61+
$adapter = new static(new \Memcached($persistentId));
62+
$adapter->setup($dsn ? array($dsn) : array(), $opts);
63+
64+
return $adapter;
65+
}
66+
67+
/**
68+
* @param string[] $dsns
69+
* @param mixed[] $opts
70+
*
71+
* @return $this
72+
*/
73+
public function setup(array $dsns = array(), array $opts = array())
74+
{
75+
foreach ($opts as $opt => $val) {
76+
$this->setOption($opt, $val);
77+
}
78+
foreach ($dsns as $dsn) {
79+
$this->addServer($dsn);
80+
}
81+
82+
return $this;
83+
}
84+
85+
/**
86+
* {@inheritdoc}
87+
*/
88+
protected function doSave(array $values, $lifetime)
89+
{
90+
return $this->client->setMulti($values, $lifetime)
91+
&& $this->client->getResultCode() === \Memcached::RES_SUCCESS;
92+
}
93+
94+
/**
95+
* {@inheritdoc}
96+
*/
97+
protected function doFetch(array $ids)
98+
{
99+
return $this->client->getMulti($ids);
100+
}
101+
102+
/**
103+
* {@inheritdoc}
104+
*/
105+
protected function doHave($id)
106+
{
107+
return $this->client->get($id) !== false
108+
|| $this->client->getResultCode() === \Memcached::RES_SUCCESS;
109+
}
110+
111+
/**
112+
* {@inheritdoc}
113+
*/
114+
protected function doDelete(array $ids)
115+
{
116+
$toDelete = count($ids);
117+
foreach ($this->client->deleteMulti($ids) as $result) {
118+
if (\Memcached::RES_SUCCESS === $result || \Memcached::RES_NOTFOUND === $result) {
119+
--$toDelete;
120+
}
121+
}
122+
123+
return 0 === $toDelete;
124+
}
125+
126+
/**
127+
* {@inheritdoc}
128+
*/
129+
protected function doClear($namespace)
130+
{
131+
return $this->client->flush();
132+
}
133+
134+
private function setOption($opt, $val)
135+
{
136+
return $this->client->setOption(
137+
$this->resolveOption($opt),
138+
$this->resolveOption($val)
139+
);
140+
}
141+
142+
private function resolveOption($val)
143+
{
144+
return defined($constant = '\Memcached::'.strtoupper($val)) ? constant($constant) : $val;
145+
}
146+
147+
private function addServer($dsn)
148+
{
149+
list($host, $port, $weight) = $this->parseServerDSN($dsn);
150+
151+
return $this->isServerInClientPool($host, $port)
152+
|| ($this->client->addServer($host, $port, $weight)
153+
&& $this->client->getResultCode() === \Memcached::RES_SUCCESS);
154+
}
155+
156+
private function parseServerDSN($dsn)
157+
{
158+
if (false === ($srv = parse_url($dsn)) || $srv['scheme'] !== 'memcached' || count($srv) > 4) {
159+
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s (expected "memcached://[<string>[:<int>]][?weight=<int>]")', $dsn));
160+
}
161+
162+
unset($srv['scheme']);
163+
$srv += self::$defaultClientServer;
164+
165+
if (isset($srv['query']) && 1 === preg_match('{weight=([^&]{1,})}', $srv['query'], $weight)) {
166+
unset($srv['query']);
167+
$srv['weight'] = (int) $weight[1];
168+
}
169+
170+
return array_values($srv);
171+
}
172+
173+
private function isServerInClientPool($host, $port)
174+
{
175+
foreach ($this->client->getServerList() as $srv) {
176+
if ($host === $srv['host'] && $port === $srv['port']) {
177+
return true;
178+
}
179+
}
180+
181+
return false;
182+
}
183+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.