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

New DSN component #36999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Connection facotry
  • Loading branch information
Nyholm committed Jun 13, 2020
commit a4d62d38fae24dfe65bbf0229eb111fa47a56019
3 changes: 3 additions & 0 deletions 3 src/Symfony/Component/Dsn/Configuration/DsnFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public function getName(): string
return $this->name;
}

/**
* @return array<DsnFunction|Dsn>
*/
public function getArguments(): array
{
return $this->arguments;
Expand Down
60 changes: 60 additions & 0 deletions 60 src/Symfony/Component/Dsn/ConnectionFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Symfony\Component\Dsn;

/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class ConnectionFactory implements ConnectionFactoryInterface
{
/**
* @var array<string> of classes implementing ConnectionFactoryInterface
*/
private static $factories = [];

public static function addFactory(string $factory, $prepend = false): void
{
if (!is_a($factory, ConnectionFactoryInterface::class, true)) {
throw new \LogicException(sprintf('Argument to "%s::addFactory()" must be a class string to a class implementing "%s".', self::class, ConnectionFactoryInterface::class));
}

if ($prepend) {
array_unshift(self::$factories, $factory);
} else {
self::$factories[] = $factory;
}
}

public static function create(string $dsn): object
{
foreach (self::$factories as $factory) {
if ($factory::supports($dsn)) {
return $factory::create($dsn);
}
}

//throw new exception
}

public static function supports(string $dsn): bool
{
foreach (self::$factories as $factory) {
if ($factory::supports($dsn)) {
return true;
}
}

return false;
}
}
24 changes: 24 additions & 0 deletions 24 src/Symfony/Component/Dsn/ConnectionFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Symfony\Component\Dsn;

/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
interface ConnectionFactoryInterface
{
public static function create(string $dsn): object;

public static function supports(string $dsn): bool;
}
51 changes: 51 additions & 0 deletions 51 src/Symfony/Component/Dsn/ConnectionRegistry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Symfony\Component\Dsn;

class ConnectionRegistry
{
/**
* @var array [dsn => Connection]
*/
private $connections = [];

/**
* @var ConnectionFactoryInterface
*/
private $factory;

public function __construct(ConnectionFactoryInterface $factory)
{
$this->factory = $factory;
}

public function addConnection(string $dsn, object $connection)
{
$this->connections[$dsn] = $connection;
}

public function has(string $dsn): bool
{
return isset($this->connections[$dsn]);
}

public function getConnection(string $dsn): object
{
if ($this->has($dsn)) {
return $this->connections[$dsn];
}

return $this->connections[$dsn] = $this->factory::create($dsn);
}
}
23 changes: 23 additions & 0 deletions 23 src/Symfony/Component/Dsn/Exception/ExceptionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Symfony\Component\Dsn\Exception;

/**
* Base ExceptionInterface for the Dsn Component.
*
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
interface ExceptionInterface
{
}
23 changes: 23 additions & 0 deletions 23 src/Symfony/Component/Dsn/Exception/InvalidArgumentException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Symfony\Component\Dsn\Exception;

/**
* Base InvalidArgumentException for the Dsn component.
*
* @author Jérémy Derussé <jeremy@derusse.com>
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
4 changes: 2 additions & 2 deletions 4 src/Symfony/Component/Dsn/Exception/InvalidDsnException.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
*
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class InvalidDsnException extends \InvalidArgumentException
class InvalidDsnException extends InvalidArgumentException
{
private $dsn;

public function __construct(string $dsn, string $message)
{
$this->dsn = $dsn;
parent::__construct(sprintf('%s. (%s)', $message, $dsn));
parent::__construct(sprintf('%s (%s)', $message, $dsn));
}

public function getDsn(): string
Expand Down
176 changes: 176 additions & 0 deletions 176 src/Symfony/Component/Dsn/Factory/MemcachedFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Symfony\Component\Dsn\Factory;

use Symfony\Component\Dsn\Configuration\Dsn;
use Symfony\Component\Dsn\Configuration\Path;
use Symfony\Component\Dsn\Configuration\Url;
use Symfony\Component\Dsn\ConnectionFactoryInterface;
use Symfony\Component\Dsn\DsnParser;
use Symfony\Component\Dsn\Exception\FunctionNotSupportedException;
use Symfony\Component\Dsn\Exception\InvalidArgumentException;

/**
* @author Nicolas Grekas <p@tchwork.com>
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
* @author Jérémy Derussé <jeremy@derusse.com>
*/
class MemcachedFactory implements ConnectionFactoryInterface
{
private static $defaultClientOptions = [
'class' => null,
'persistent_id' => null,
'username' => null,
'password' => null,
'serializer' => 'php',
];

/**
* Example DSN strings.
*
* - memcached://localhost:11222?retry_timeout=10
* - memcached(memcached://127.0.0.1)?persistent_id=foobar
* - memcached(memcached://127.0.0.1 memcached://127.0.0.2?retry_timeout=10)?persistent_id=foobar
*/
public static function create(string $dsnString): object
{
$rootDsn = DsnParser::parseFunc($dsnString);
if ('dsn' !== $rootDsn->getName() && 'memcached' !== $rootDsn->getName()) {
throw new FunctionNotSupportedException($dsnString, $rootDsn->getName());
}

set_error_handler(function ($type, $msg, $file, $line) { throw new \ErrorException($msg, 0, $type, $file, $line); });

try {
$options = $rootDsn->getParameters() + static::$defaultClientOptions;

$class = null === $options['class'] ? \Memcached::class : $options['class'];
unset($options['class']);
if (is_a($class, \Memcached::class, true)) {
$client = new $class($options['persistent_id']);
} elseif (class_exists($class, false)) {
throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Memcached".', $class));
} else {
throw new InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}

$username = $options['username'];
$password = $options['password'];

$servers = [];
foreach ($rootDsn->getArguments() as $dsn) {
if (!$dsn instanceof Dsn) {
throw new InvalidArgumentException('Only one DSN function is allowed.');
}

if ('memcached' !== $dsn->getScheme()) {
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s" does not start with "memcached://".', $dsn));
}

$username = $dsn->getUser() ?? $username;
$password = $dsn->getPassword() ?? $password;
$path = $dsn->getPath();
$params['weight'] = 0;

if (null !== $path && preg_match('#/(\d+)$#', $path, $m)) {
$params['weight'] = $m[1];
$path = substr($path, 0, -\strlen($m[0]));
}

if ($dsn instanceof Url) {
$servers[] = [$dsn->getHost(), $dsn->getPort() ?? 11211, $params['weight']];
} elseif ($dsn instanceof Path) {
$params['host'] = $path;
$servers[] = [$path, null, $params['weight']];
} else {
foreach ($dsn->getParameter('hosts', []) as $host => $weight) {
if (false === $port = strrpos($host, ':')) {
$hosts[$host] = [$host, 11211, (int) $weight];
} else {
$hosts[$host] = [substr($host, 0, $port), (int) substr($host, 1 + $port), (int) $weight];
}
}
$servers = array_merge($servers, array_values($hosts));
}

$params += $dsn->getParameters();
$options = $dsn->getParameters() + $options;
}

// set client's options
unset($options['persistent_id'], $options['username'], $options['password'], $options['weight'], $options['lazy']);
$options = array_change_key_case($options, CASE_UPPER);
$client->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
$client->setOption(\Memcached::OPT_NO_BLOCK, true);
$client->setOption(\Memcached::OPT_TCP_NODELAY, true);
if (!\array_key_exists('LIBKETAMA_COMPATIBLE', $options) && !\array_key_exists(\Memcached::OPT_LIBKETAMA_COMPATIBLE, $options)) {
$client->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
}
foreach ($options as $name => $value) {
if (\is_int($name)) {
continue;
}
if ('HASH' === $name || 'SERIALIZER' === $name || 'DISTRIBUTION' === $name) {
$value = \constant('Memcached::'.$name.'_'.strtoupper($value));
}
$opt = \constant('Memcached::OPT_'.$name);

unset($options[$name]);
$options[$opt] = $value;
}
$client->setOptions($options);

// set client's servers, taking care of persistent connections
if (!$client->isPristine()) {
$oldServers = [];
foreach ($client->getServerList() as $server) {
$oldServers[] = [$server['host'], $server['port']];
}

$newServers = [];
foreach ($servers as $server) {
if (1 < \count($server)) {
$server = array_values($server);
unset($server[2]);
$server[1] = (int) $server[1];
}
$newServers[] = $server;
}

if ($oldServers !== $newServers) {
$client->resetServerList();
$client->addServers($servers);
}
} else {
$client->addServers($servers);
}

if (null !== $username || null !== $password) {
if (!method_exists($client, 'setSaslAuthData')) {
trigger_error('Missing SASL support: the memcached extension must be compiled with --enable-memcached-sasl.');
}
$client->setSaslAuthData($username, $password);
}

return $client;
} finally {
restore_error_handler();
}
}

public static function supports(string $dsn): bool
{
return 0 !== strpos($dsn, 'memcached:');
}
}
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.