mirror of
				https://github.com/elyby/accounts.git
				synced 2025-05-31 14:11:46 +05:30 
			
		
		
		
	Rework identity provider for the legacy OAuth2 tokens [skip ci]
This commit is contained in:
		@@ -11,9 +11,6 @@ use League\OAuth2\Server\AuthorizationServer;
 | 
			
		||||
use League\OAuth2\Server\Grant;
 | 
			
		||||
use yii\base\Component as BaseComponent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @property AuthorizationServer $authServer
 | 
			
		||||
 */
 | 
			
		||||
class Component extends BaseComponent {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -39,7 +36,6 @@ class Component extends BaseComponent {
 | 
			
		||||
                new EmptyKey(),
 | 
			
		||||
                '123' // TODO: extract to the variable
 | 
			
		||||
            );
 | 
			
		||||
            /** @noinspection PhpUnhandledExceptionInspection */
 | 
			
		||||
            $authCodeGrant = new AuthCodeGrant($authCodesRepo, $refreshTokensRepo, new DateInterval('PT10M'));
 | 
			
		||||
            $authCodeGrant->disableRequireCodeChallengeForPublicClients();
 | 
			
		||||
            $authServer->enableGrantType($authCodeGrant, $accessTokenTTL);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,70 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\components\OAuth2\Repositories;
 | 
			
		||||
 | 
			
		||||
use api\components\OAuth2\Entities\AccessTokenEntity;
 | 
			
		||||
use common\components\Redis\Key;
 | 
			
		||||
use common\components\Redis\Set;
 | 
			
		||||
use League\OAuth2\Server\Entity\AccessTokenEntity as OriginalAccessTokenEntity;
 | 
			
		||||
use League\OAuth2\Server\Entity\ScopeEntity;
 | 
			
		||||
use League\OAuth2\Server\Storage\AbstractStorage;
 | 
			
		||||
use League\OAuth2\Server\Storage\AccessTokenInterface;
 | 
			
		||||
use yii\helpers\Json;
 | 
			
		||||
 | 
			
		||||
class AccessTokenStorage extends AbstractStorage implements AccessTokenInterface {
 | 
			
		||||
 | 
			
		||||
    public $dataTable = 'oauth_access_tokens';
 | 
			
		||||
 | 
			
		||||
    public function get($token) {
 | 
			
		||||
        $result = Json::decode((new Key($this->dataTable, $token))->getValue());
 | 
			
		||||
        if ($result === null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $token = new AccessTokenEntity($this->server);
 | 
			
		||||
        $token->setId($result['id']);
 | 
			
		||||
        $token->setExpireTime($result['expire_time']);
 | 
			
		||||
        $token->setSessionId($result['session_id']);
 | 
			
		||||
 | 
			
		||||
        return $token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getScopes(OriginalAccessTokenEntity $token) {
 | 
			
		||||
        $scopes = $this->scopes($token->getId());
 | 
			
		||||
        $entities = [];
 | 
			
		||||
        foreach ($scopes as $scope) {
 | 
			
		||||
            if ($this->server->getScopeStorage()->get($scope) !== null) {
 | 
			
		||||
                $entities[] = (new ScopeEntity($this->server))->hydrate(['id' => $scope]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $entities;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function create($token, $expireTime, $sessionId) {
 | 
			
		||||
        $payload = Json::encode([
 | 
			
		||||
            'id' => $token,
 | 
			
		||||
            'expire_time' => $expireTime,
 | 
			
		||||
            'session_id' => $sessionId,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $this->key($token)->setValue($payload)->expireAt($expireTime);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function associateScope(OriginalAccessTokenEntity $token, ScopeEntity $scope) {
 | 
			
		||||
        $this->scopes($token->getId())->add($scope->getId())->expireAt($token->getExpireTime());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function delete(OriginalAccessTokenEntity $token) {
 | 
			
		||||
        $this->key($token->getId())->delete();
 | 
			
		||||
        $this->scopes($token->getId())->delete();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function key(string $token): Key {
 | 
			
		||||
        return new Key($this->dataTable, $token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function scopes(string $token): Set {
 | 
			
		||||
        return new Set($this->dataTable, $token, 'scopes');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -8,19 +8,24 @@ use yii\web\UnauthorizedHttpException;
 | 
			
		||||
class IdentityFactory {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @throws UnauthorizedHttpException
 | 
			
		||||
     * @param string $token
 | 
			
		||||
     * @param string $type
 | 
			
		||||
     *
 | 
			
		||||
     * @return IdentityInterface
 | 
			
		||||
     * @throws UnauthorizedHttpException
 | 
			
		||||
     */
 | 
			
		||||
    public static function findIdentityByAccessToken($token, $type = null): IdentityInterface {
 | 
			
		||||
        if (empty($token)) {
 | 
			
		||||
            throw new UnauthorizedHttpException('Incorrect token');
 | 
			
		||||
        if (!empty($token)) {
 | 
			
		||||
            if (mb_strlen($token) === 40) {
 | 
			
		||||
                return LegacyOAuth2Identity::findIdentityByAccessToken($token, $type);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (substr_count($token, '.') === 2) {
 | 
			
		||||
                return JwtIdentity::findIdentityByAccessToken($token, $type);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (substr_count($token, '.') === 2) {
 | 
			
		||||
            return JwtIdentity::findIdentityByAccessToken($token, $type);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return OAuth2Identity::findIdentityByAccessToken($token, $type);
 | 
			
		||||
        throw new UnauthorizedHttpException('Incorrect token');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										119
									
								
								api/components/User/LegacyOAuth2Identity.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								api/components/User/LegacyOAuth2Identity.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace api\components\User;
 | 
			
		||||
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\OauthSession;
 | 
			
		||||
use Exception;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\base\NotSupportedException;
 | 
			
		||||
use yii\web\UnauthorizedHttpException;
 | 
			
		||||
 | 
			
		||||
class LegacyOAuth2Identity implements IdentityInterface {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    private $accessToken;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    private $sessionId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string[]
 | 
			
		||||
     */
 | 
			
		||||
    private $scopes;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var OauthSession|null
 | 
			
		||||
     */
 | 
			
		||||
    private $session = false;
 | 
			
		||||
 | 
			
		||||
    private function __construct(string $accessToken, string $sessionId, array $scopes) {
 | 
			
		||||
        $this->accessToken = $accessToken;
 | 
			
		||||
        $this->sessionId = $sessionId;
 | 
			
		||||
        $this->scopes = $scopes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     * @throws UnauthorizedHttpException
 | 
			
		||||
     * @return IdentityInterface
 | 
			
		||||
     */
 | 
			
		||||
    public static function findIdentityByAccessToken($token, $type = null): IdentityInterface {
 | 
			
		||||
        $tokenParams = self::findRecordOnLegacyStorage($token);
 | 
			
		||||
        if ($tokenParams === null) {
 | 
			
		||||
            throw new UnauthorizedHttpException('Incorrect token');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($tokenParams['expire_time'] < time()) {
 | 
			
		||||
            throw new UnauthorizedHttpException('Token expired');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new static($token, $tokenParams['session_id'], $tokenParams['scopes']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAccount(): ?Account {
 | 
			
		||||
        $session = $this->getSession();
 | 
			
		||||
        if ($session === null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $session->account;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return string[]
 | 
			
		||||
     */
 | 
			
		||||
    public function getAssignedPermissions(): array {
 | 
			
		||||
        return $this->scopes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getId(): string {
 | 
			
		||||
        return $this->accessToken;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @codeCoverageIgnoreStart
 | 
			
		||||
    public function getAuthKey() {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function validateAuthKey($authKey) {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function findIdentity($id) {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @codeCoverageIgnoreEnd
 | 
			
		||||
 | 
			
		||||
    private static function findRecordOnLegacyStorage(string $accessToken): ?array {
 | 
			
		||||
        $record = Yii::$app->redis->get("oauth:access:tokens:{$accessToken}");
 | 
			
		||||
        if ($record === null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $data = json_decode($record, true, 512, JSON_THROW_ON_ERROR);
 | 
			
		||||
        } catch (Exception $e) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $data['scopes'] = (array)Yii::$app->redis->smembers("oauth:access:tokens:{$accessToken}:scopes");
 | 
			
		||||
 | 
			
		||||
        return $data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function getSession(): ?OauthSession {
 | 
			
		||||
        if ($this->session === false) {
 | 
			
		||||
            $this->session = OauthSession::findOne(['id' => $this->sessionId]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->session;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,78 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace api\components\User;
 | 
			
		||||
 | 
			
		||||
use api\components\OAuth2\Entities\AccessTokenEntity;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\OauthSession;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\base\NotSupportedException;
 | 
			
		||||
use yii\web\UnauthorizedHttpException;
 | 
			
		||||
 | 
			
		||||
class OAuth2Identity implements IdentityInterface {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var AccessTokenEntity
 | 
			
		||||
     */
 | 
			
		||||
    private $_accessToken;
 | 
			
		||||
 | 
			
		||||
    private function __construct(AccessTokenEntity $accessToken) {
 | 
			
		||||
        $this->_accessToken = $accessToken;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     * @throws UnauthorizedHttpException
 | 
			
		||||
     * @return IdentityInterface
 | 
			
		||||
     */
 | 
			
		||||
    public static function findIdentityByAccessToken($token, $type = null): IdentityInterface {
 | 
			
		||||
        /** @var AccessTokenEntity|null $model */
 | 
			
		||||
        // TODO: rework
 | 
			
		||||
        $model = Yii::$app->oauth->getAccessTokenStorage()->get($token);
 | 
			
		||||
        if ($model === null) {
 | 
			
		||||
            throw new UnauthorizedHttpException('Incorrect token');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($model->isExpired()) {
 | 
			
		||||
            throw new UnauthorizedHttpException('Token expired');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new static($model);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAccount(): ?Account {
 | 
			
		||||
        return $this->getSession()->account;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return string[]
 | 
			
		||||
     */
 | 
			
		||||
    public function getAssignedPermissions(): array {
 | 
			
		||||
        return array_keys($this->_accessToken->getScopes());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getId(): string {
 | 
			
		||||
        return $this->_accessToken->getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @codeCoverageIgnoreStart
 | 
			
		||||
    public function getAuthKey() {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function validateAuthKey($authKey) {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function findIdentity($id) {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @codeCoverageIgnoreEnd
 | 
			
		||||
 | 
			
		||||
    private function getSession(): OauthSession {
 | 
			
		||||
        return OauthSession::findOne(['id' => $this->_accessToken->getSessionId()]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,7 @@ namespace codeception\api\unit\components\User;
 | 
			
		||||
 | 
			
		||||
use api\components\User\Component;
 | 
			
		||||
use api\components\User\JwtIdentity;
 | 
			
		||||
use api\components\User\OAuth2Identity;
 | 
			
		||||
use api\components\User\LegacyOAuth2Identity;
 | 
			
		||||
use api\tests\unit\TestCase;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\AccountSession;
 | 
			
		||||
@@ -41,7 +41,7 @@ class ComponentTest extends TestCase {
 | 
			
		||||
        $this->assertNull($component->getActiveSession());
 | 
			
		||||
 | 
			
		||||
        // Identity is a Oauth2Identity
 | 
			
		||||
        $component->setIdentity(mock(OAuth2Identity::class));
 | 
			
		||||
        $component->setIdentity(mock(LegacyOAuth2Identity::class));
 | 
			
		||||
        $this->assertNull($component->getActiveSession());
 | 
			
		||||
 | 
			
		||||
        // Identity is correct, but have no jti claim
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ use api\components\OAuth2\Component;
 | 
			
		||||
use api\components\OAuth2\Entities\AccessTokenEntity;
 | 
			
		||||
use api\components\User\IdentityFactory;
 | 
			
		||||
use api\components\User\JwtIdentity;
 | 
			
		||||
use api\components\User\OAuth2Identity;
 | 
			
		||||
use api\components\User\LegacyOAuth2Identity;
 | 
			
		||||
use api\tests\unit\TestCase;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use League\OAuth2\Server\AbstractServer;
 | 
			
		||||
@@ -37,7 +37,7 @@ class IdentityFactoryTest extends TestCase {
 | 
			
		||||
        Yii::$app->set('oauth', $component);
 | 
			
		||||
 | 
			
		||||
        $identity = IdentityFactory::findIdentityByAccessToken('mock-token');
 | 
			
		||||
        $this->assertInstanceOf(OAuth2Identity::class, $identity);
 | 
			
		||||
        $this->assertInstanceOf(LegacyOAuth2Identity::class, $identity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFindIdentityByAccessTokenWithEmptyValue() {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,12 @@ namespace api\tests\unit\components\User;
 | 
			
		||||
 | 
			
		||||
use api\components\OAuth2\Component;
 | 
			
		||||
use api\components\OAuth2\Entities\AccessTokenEntity;
 | 
			
		||||
use api\components\User\OAuth2Identity;
 | 
			
		||||
use api\components\User\LegacyOAuth2Identity;
 | 
			
		||||
use api\tests\unit\TestCase;
 | 
			
		||||
use League\OAuth2\Server\AbstractServer;
 | 
			
		||||
use League\OAuth2\Server\Storage\AccessTokenInterface;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\web\UnauthorizedHttpException;
 | 
			
		||||
 | 
			
		||||
class OAuth2IdentityTest extends TestCase {
 | 
			
		||||
class LegacyOAuth2IdentityTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function testFindIdentityByAccessToken() {
 | 
			
		||||
        $accessToken = new AccessTokenEntity(mock(AbstractServer::class));
 | 
			
		||||
@@ -20,7 +18,7 @@ class OAuth2IdentityTest extends TestCase {
 | 
			
		||||
        $accessToken->setId('mock-token');
 | 
			
		||||
        $this->mockFoundedAccessToken($accessToken);
 | 
			
		||||
 | 
			
		||||
        $identity = OAuth2Identity::findIdentityByAccessToken('mock-token');
 | 
			
		||||
        $identity = LegacyOAuth2Identity::findIdentityByAccessToken('mock-token');
 | 
			
		||||
        $this->assertSame('mock-token', $identity->getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +26,7 @@ class OAuth2IdentityTest extends TestCase {
 | 
			
		||||
        $this->expectException(UnauthorizedHttpException::class);
 | 
			
		||||
        $this->expectExceptionMessage('Incorrect token');
 | 
			
		||||
 | 
			
		||||
        OAuth2Identity::findIdentityByAccessToken('not exists token');
 | 
			
		||||
        LegacyOAuth2Identity::findIdentityByAccessToken('not exists token');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFindIdentityByAccessTokenWithExpiredToken() {
 | 
			
		||||
@@ -39,7 +37,7 @@ class OAuth2IdentityTest extends TestCase {
 | 
			
		||||
        $accessToken->setExpireTime(time() - 3600);
 | 
			
		||||
        $this->mockFoundedAccessToken($accessToken);
 | 
			
		||||
 | 
			
		||||
        OAuth2Identity::findIdentityByAccessToken('mock-token');
 | 
			
		||||
        LegacyOAuth2Identity::findIdentityByAccessToken('mock-token');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function mockFoundedAccessToken(AccessTokenEntity $accessToken) {
 | 
			
		||||
@@ -1,63 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace common\components\Redis;
 | 
			
		||||
 | 
			
		||||
use InvalidArgumentException;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @deprecated
 | 
			
		||||
 */
 | 
			
		||||
class Key {
 | 
			
		||||
 | 
			
		||||
    private $key;
 | 
			
		||||
 | 
			
		||||
    public function __construct(...$key) {
 | 
			
		||||
        if (empty($key)) {
 | 
			
		||||
            throw new InvalidArgumentException('You must specify at least one key.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->key = $this->buildKey($key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getKey(): string {
 | 
			
		||||
        return $this->key;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getValue() {
 | 
			
		||||
        return Yii::$app->redis->get($this->key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setValue($value): self {
 | 
			
		||||
        Yii::$app->redis->set($this->key, $value);
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function delete(): self {
 | 
			
		||||
        Yii::$app->redis->del($this->getKey());
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function exists(): bool {
 | 
			
		||||
        return (bool)Yii::$app->redis->exists($this->key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function expire(int $ttl): self {
 | 
			
		||||
        Yii::$app->redis->expire($this->key, $ttl);
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function expireAt(int $unixTimestamp): self {
 | 
			
		||||
        Yii::$app->redis->expireat($this->key, $unixTimestamp);
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function buildKey(array $parts): string {
 | 
			
		||||
        $keyParts = [];
 | 
			
		||||
        foreach ($parts as $part) {
 | 
			
		||||
            $keyParts[] = str_replace('_', ':', $part);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return implode(':', $keyParts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace common\components\Redis;
 | 
			
		||||
 | 
			
		||||
use ArrayIterator;
 | 
			
		||||
use IteratorAggregate;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @deprecated
 | 
			
		||||
 */
 | 
			
		||||
class Set extends Key implements IteratorAggregate {
 | 
			
		||||
 | 
			
		||||
    public function add($value): self {
 | 
			
		||||
        Yii::$app->redis->sadd($this->getKey(), $value);
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function remove($value): self {
 | 
			
		||||
        Yii::$app->redis->srem($this->getKey(), $value);
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function members(): array {
 | 
			
		||||
        return Yii::$app->redis->smembers($this->getKey());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getValue(): array {
 | 
			
		||||
        return $this->members();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function exists(string $value = null): bool {
 | 
			
		||||
        if ($value === null) {
 | 
			
		||||
            return parent::exists();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (bool)Yii::$app->redis->sismember($this->getKey(), $value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function diff(array $sets): array {
 | 
			
		||||
        return Yii::$app->redis->sdiff([$this->getKey(), implode(' ', $sets)]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    public function getIterator() {
 | 
			
		||||
        return new ArrayIterator($this->members());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user