Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 444f9fc

Browse files
committed
support memcached dsn using new memcacheclient factory helper
1 parent 9f95654 commit 444f9fc

File tree

4 files changed

+438
-11
lines changed

4 files changed

+438
-11
lines changed
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Client;
13+
14+
use Symfony\Component\Cache\Exception\InvalidArgumentException;
15+
16+
/**
17+
* @author Rob Frawley 2nd <[email protected]>
18+
*
19+
* @internal
20+
*/
21+
final class MemcachedClient
22+
{
23+
private static $serverDefaults = array(
24+
'host' => 'localhost',
25+
'port' => 11211,
26+
'weight' => 100,
27+
);
28+
29+
private static $optionDefaults = array(
30+
'compression' => true,
31+
'libketama_compatible' => true,
32+
'binary_protocol' => true,
33+
);
34+
35+
private $client;
36+
private $errorLevel;
37+
38+
public function __construct(array $servers = array(), array $options = array())
39+
{
40+
$this->client = new \Memcached(isset($options['persistent_id']) ? $options['persistent_id'] : null);
41+
$this->setOptions($options);
42+
$this->setServers($servers);
43+
}
44+
45+
/**
46+
* @return \Memcached
47+
*/
48+
public static function create($servers = array(), array $options = array())
49+
{
50+
return (new static(is_array($servers) ? $servers : array($servers), $options))->getClient();
51+
}
52+
53+
public static function isSupported()
54+
{
55+
return extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>=');
56+
}
57+
58+
public function getClient()
59+
{
60+
return $this->client;
61+
}
62+
63+
private function setOptions(array $options)
64+
{
65+
unset($options['persistent_id']);
66+
$options += static::$optionDefaults;
67+
68+
foreach ($options as $named => $value) {
69+
$this->addOption($named, $value);
70+
}
71+
}
72+
73+
private function addOption($named, $value)
74+
{
75+
$this->silenceErrorInitialize();
76+
$result = $this->client->setOption($this->resolveOptionNamed($named), $this->resolveOptionValue($named, $value));
77+
$this->silenceErrorRestoreAct(!$result, 'Invalid option: %s=%s', array(var_export($named, true), var_export($value, true)));
78+
}
79+
80+
private function resolveOptionNamed($named)
81+
{
82+
if (!defined($constant = sprintf('\Memcached::OPT_%s', strtoupper($named)))) {
83+
throw new InvalidArgumentException(sprintf('Invalid option named: %s', $named));
84+
}
85+
86+
return constant($constant);
87+
}
88+
89+
private function resolveOptionValue($named, $value)
90+
{
91+
$typed = preg_replace('{_.*$}', '', $named);
92+
93+
if (defined($constant = sprintf('\Memcached::%s_%s', strtoupper($typed), strtoupper($value)))
94+
|| defined($constant = sprintf('\Memcached::%s', strtoupper($value)))) {
95+
return constant($constant);
96+
}
97+
98+
return $value;
99+
}
100+
101+
private function setServers(array $dsns)
102+
{
103+
foreach ($dsns as $i => $dsn) {
104+
$this->addServer($i, $dsn);
105+
}
106+
}
107+
108+
private function addServer($i, $dsn)
109+
{
110+
if (false === $server = $this->resolveServer($dsn)) {
111+
throw new InvalidArgumentException(sprintf('Invalid server %d DSN: %s', $i, $dsn));
112+
}
113+
114+
if ($this->hasServer($server['host'], $server['port'])) {
115+
return;
116+
}
117+
118+
if (isset($server['user']) && isset($server['port'])) {
119+
$this->setServerAuthentication($server['user'], $server['pass']);
120+
}
121+
122+
$this->client->addServer($server['host'], $server['port'], $server['weight']);
123+
}
124+
125+
private function hasServer($host, $port)
126+
{
127+
foreach ($this->client->getServerList() as $server) {
128+
if ($server['host'] === $host && $server['port'] === $port) {
129+
return true;
130+
}
131+
}
132+
133+
return false;
134+
}
135+
136+
private function setServerAuthentication($user, $pass)
137+
{
138+
$this->silenceErrorInitialize();
139+
$result = $this->client->setSaslAuthData($user, $pass);
140+
$this->silenceErrorRestoreAct(!$result, 'Could not set SASL authentication:');
141+
}
142+
143+
private function resolveServer($dsn)
144+
{
145+
if (0 !== strpos($dsn, 'memcached')) {
146+
return false;
147+
}
148+
149+
if (false !== $server = $this->resolveServerAsHost($dsn)) {
150+
return $server;
151+
}
152+
153+
return $this->resolveServerAsSock($dsn);
154+
}
155+
156+
private function resolveServerAsHost($dsn)
157+
{
158+
if (false === $server = parse_url($dsn)) {
159+
return false;
160+
}
161+
162+
return $this->resolveServerCommon($server);
163+
}
164+
165+
private function resolveServerAsSock($dsn)
166+
{
167+
if (1 !== preg_match('{memcached:\/\/(?:(?<user>.+?):(?<pass>.+?)@)?(?<host>\/[^?]+)(?:\?)?(?<query>.+)?}', $dsn, $server)) {
168+
return false;
169+
}
170+
171+
if (0 === strpos(strrev($server['host']), '/')) {
172+
$server['host'] = substr($server['host'], 0, -1);
173+
}
174+
175+
return $this->resolveServerCommon(array_filter($server, function ($v, $i) {
176+
return !is_int($i) && !empty($v);
177+
}, ARRAY_FILTER_USE_BOTH));
178+
}
179+
180+
private function resolveServerCommon($server)
181+
{
182+
parse_str(isset($server['query']) ? $server['query'] : '', $query);
183+
184+
$server += array_filter($query, function ($index) {
185+
return in_array($index, array('weight'));
186+
}, ARRAY_FILTER_USE_KEY);
187+
188+
$server += static::$serverDefaults;
189+
190+
return array_filter($server, function ($index) {
191+
return in_array($index, array('host', 'port', 'weight', 'user', 'pass'));
192+
}, ARRAY_FILTER_USE_KEY);
193+
}
194+
195+
private function silenceErrorInitialize()
196+
{
197+
$this->errorLevel = error_reporting(~E_ALL);
198+
}
199+
200+
private function silenceErrorRestoreAct($throwError, $format, array $replacements = array())
201+
{
202+
error_reporting($this->errorLevel);
203+
204+
if ($throwError) {
205+
$errorRet = error_get_last();
206+
$errorMsg = isset($errorRet['message']) ? $errorRet['message'] : $this->client->getResultMessage();
207+
208+
throw new InvalidArgumentException(vsprintf($format.' (%s)', array_merge($replacements, array($errorMsg))));
209+
}
210+
}
211+
}

src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Cache\Adapter;
1313

14+
use Symfony\Component\Cache\Adapter\Client\MemcachedClient;
15+
1416
/**
1517
* @author Rob Frawley 2nd <[email protected]>
1618
*/
@@ -24,9 +26,15 @@ public function __construct(\Memcached $client, $namespace = '', $defaultLifetim
2426
$this->client = $client;
2527
}
2628

27-
public static function isSupported()
29+
/**
30+
* @param string[] $servers
31+
* @param mixed[] $options
32+
*
33+
* @return \Memcached
34+
*/
35+
public static function createConnection($servers = array(), array $options = array())
2836
{
29-
return extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>=');
37+
return MemcachedClient::create($servers, $options);
3038
}
3139

3240
/**
@@ -75,4 +83,13 @@ protected function doClear($namespace)
7583
{
7684
return $this->client->flush();
7785
}
86+
87+
public function __destruct()
88+
{
89+
parent::__destruct();
90+
91+
if (!$this->client->isPersistent() && method_exists($this->client, 'flushBuffers')) {
92+
$this->client->flushBuffers();
93+
}
94+
}
7895
}

0 commit comments

Comments
 (0)