Skip to content

Commit b9c0473

Browse files
committed
Merge remote-tracking branch 'origin/MC-30397' into 2.4-develop-pr9
2 parents 606c3e8 + 2214a2d commit b9c0473

File tree

2 files changed

+125
-110
lines changed

2 files changed

+125
-110
lines changed

dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandlerTest.php

Lines changed: 68 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,25 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Framework\Session;
78

89
use Magento\Framework\App\DeploymentConfig;
910
use Magento\Framework\Exception\SessionException;
1011
use Magento\Framework\Phrase;
1112
use Magento\Framework\Session\Config\ConfigInterface;
12-
use Magento\Framework\App\ObjectManager;
13+
use Magento\TestFramework\Helper\Bootstrap;
14+
use Magento\TestFramework\ObjectManager;
1315

16+
/**
17+
* Tests \Magento\Framework\Session\SaveHandler functionality.
18+
*
19+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
20+
*/
1421
class SaveHandlerTest extends \PHPUnit\Framework\TestCase
1522
{
1623
/**
17-
* @var \Magento\TestFramework\ObjectManager
24+
* @var ObjectManager
1825
*/
1926
private $objectManager;
2027

@@ -28,115 +35,96 @@ class SaveHandlerTest extends \PHPUnit\Framework\TestCase
2835
*/
2936
private $saveHandlerFactoryMock;
3037

38+
/**
39+
* @inheritdoc
40+
*/
3141
protected function setUp()
3242
{
33-
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
43+
$this->objectManager = Bootstrap::getObjectManager();
3444
$this->deploymentConfigMock = $this->createMock(DeploymentConfig::class);
3545
$this->objectManager->addSharedInstance($this->deploymentConfigMock, DeploymentConfig::class);
3646
$this->saveHandlerFactoryMock = $this->createMock(SaveHandlerFactory::class);
3747
$this->objectManager->addSharedInstance($this->saveHandlerFactoryMock, SaveHandlerFactory::class);
3848
}
3949

50+
/**
51+
* @inheritdoc
52+
*/
4053
protected function tearDown()
4154
{
4255
$this->objectManager->removeSharedInstance(DeploymentConfig::class);
4356
$this->objectManager->removeSharedInstance(SaveHandlerFactory::class);
4457
}
4558

4659
/**
47-
* Tests that the session handler is correctly set when object is created.
48-
*
49-
* @dataProvider saveHandlerProvider
50-
* @param string $deploymentConfigHandler
60+
* @return void
5161
*/
52-
public function testConstructor($deploymentConfigHandler)
62+
public function testRedisSaveHandler(): void
5363
{
54-
$expected = $this->getExpectedSaveHandler($deploymentConfigHandler, ini_get('session.save_handler'));
55-
5664
$this->deploymentConfigMock->method('get')
57-
->willReturnCallback(function ($configPath) use ($deploymentConfigHandler) {
58-
switch ($configPath) {
59-
case Config::PARAM_SESSION_SAVE_METHOD:
60-
return $deploymentConfigHandler;
61-
case Config::PARAM_SESSION_CACHE_LIMITER:
62-
return 'private_no_expire';
63-
case Config::PARAM_SESSION_SAVE_PATH:
64-
return 'explicit_save_path';
65-
default:
66-
return null;
67-
}
68-
});
69-
70-
$this->saveHandlerFactoryMock->expects($this->once())
71-
->method('create')
72-
->with($expected);
73-
$sessionConfig = $this->objectManager->create(ConfigInterface::class);
74-
$this->objectManager->create(SaveHandler::class, ['sessionConfig' => $sessionConfig]);
65+
->willReturnMap(
66+
[
67+
[Config::PARAM_SESSION_SAVE_METHOD, null, 'redis'],
68+
[Config::PARAM_SESSION_SAVE_PATH, null, 'explicit_save_path'],
69+
]
70+
);
7571

76-
// Test expectation
77-
$this->assertEquals(
78-
$expected,
79-
$sessionConfig->getOption('session.save_handler')
80-
);
81-
}
72+
$redisHandlerMock = $this->getMockBuilder(SaveHandler\Redis::class)
73+
->disableOriginalConstructor()
74+
->getMock();
75+
$redisHandlerMock->method('open')
76+
->with('explicit_save_path', 'test_session_id')
77+
->willReturn(true);
8278

83-
public function saveHandlerProvider()
84-
{
85-
return [
86-
['db'],
87-
['redis'],
88-
['files'],
89-
[false],
90-
];
79+
$this->saveHandlerFactoryMock->expects($this->exactly(1))
80+
->method('create')
81+
->with('redis')
82+
->willReturn($redisHandlerMock);
83+
84+
$sessionConfig = $this->objectManager->create(ConfigInterface::class);
85+
/** @var SaveHandler $saveHandler */
86+
$saveHandler = $this->objectManager->create(SaveHandler::class, ['sessionConfig' => $sessionConfig]);
87+
$result = $saveHandler->open('explicit_save_path', 'test_session_id');
88+
$this->assertTrue($result);
9189
}
9290

9391
/**
94-
* Retrieve expected session.save_handler
95-
*
96-
* @param string $deploymentConfigHandler
97-
* @param string $iniHandler
98-
* @return string
92+
* @return void
9993
*/
100-
private function getExpectedSaveHandler($deploymentConfigHandler, $iniHandler)
101-
{
102-
if ($deploymentConfigHandler) {
103-
return $deploymentConfigHandler;
104-
} elseif ($iniHandler) {
105-
return $iniHandler;
106-
} else {
107-
return SaveHandlerInterface::DEFAULT_HANDLER;
108-
}
109-
}
110-
111-
public function testConstructorWithException()
94+
public function testRedisSaveHandlerFallbackToDefaultOnSessionException(): void
11295
{
11396
$this->deploymentConfigMock->method('get')
114-
->willReturnCallback(function ($configPath) {
115-
switch ($configPath) {
116-
case Config::PARAM_SESSION_SAVE_METHOD:
117-
return 'db';
118-
case Config::PARAM_SESSION_CACHE_LIMITER:
119-
return 'private_no_expire';
120-
case Config::PARAM_SESSION_SAVE_PATH:
121-
return 'explicit_save_path';
122-
default:
123-
return null;
124-
}
125-
});
97+
->willReturnMap(
98+
[
99+
[Config::PARAM_SESSION_SAVE_METHOD, null, 'redis'],
100+
[Config::PARAM_SESSION_SAVE_PATH, null, 'explicit_save_path'],
101+
]
102+
);
103+
104+
$redisHandlerMock = $this->getMockBuilder(SaveHandler\Redis::class)
105+
->disableOriginalConstructor()
106+
->getMock();
107+
$redisHandlerMock->method('open')
108+
->with('explicit_save_path', 'test_session_id')
109+
->willThrowException(new SessionException(new Phrase('Session Exception')));
110+
111+
$defaultHandlerMock = $this->getMockBuilder(SaveHandler\Native::class)
112+
->disableOriginalConstructor()
113+
->getMock();
114+
$defaultHandlerMock->expects($this->once())->method('open')->with('explicit_save_path', 'test_session_id');
126115

127116
$this->saveHandlerFactoryMock->expects($this->at(0))
128117
->method('create')
129-
->willThrowException(new SessionException(new Phrase('Session Exception')));
118+
->with('redis')
119+
->willReturn($redisHandlerMock);
130120
$this->saveHandlerFactoryMock->expects($this->at(1))
131121
->method('create')
132-
->with(SaveHandlerInterface::DEFAULT_HANDLER);
133-
$sessionConfig = $this->objectManager->create(ConfigInterface::class);
134-
$this->objectManager->create(SaveHandler::class, ['sessionConfig' => $sessionConfig]);
122+
->with(SaveHandlerInterface::DEFAULT_HANDLER)
123+
->willReturn($defaultHandlerMock);
135124

136-
// Test expectation
137-
$this->assertEquals(
138-
'db',
139-
$sessionConfig->getOption('session.save_handler')
140-
);
125+
$sessionConfig = $this->objectManager->create(ConfigInterface::class);
126+
/** @var SaveHandler $saveHandler */
127+
$saveHandler = $this->objectManager->create(SaveHandler::class, ['sessionConfig' => $sessionConfig]);
128+
$saveHandler->open('explicit_save_path', 'test_session_id');
141129
}
142130
}

lib/internal/Magento/Framework/Session/SaveHandler.php

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Framework\Session;
78

89
use Magento\Framework\Session\Config\ConfigInterface;
9-
use \Magento\Framework\Exception\SessionException;
10+
use Magento\Framework\Exception\SessionException;
1011

1112
/**
12-
* Magento session save handler
13+
* Magento session save handler.
1314
*/
1415
class SaveHandler implements SaveHandlerInterface
1516
{
@@ -21,8 +22,21 @@ class SaveHandler implements SaveHandlerInterface
2122
protected $saveHandlerAdapter;
2223

2324
/**
24-
* Constructor
25-
*
25+
* @var SaveHandlerFactory
26+
*/
27+
private $saveHandlerFactory;
28+
29+
/**
30+
* @var ConfigInterface
31+
*/
32+
private $sessionConfig;
33+
34+
/**
35+
* @var string
36+
*/
37+
private $defaultHandler;
38+
39+
/**
2640
* @param SaveHandlerFactory $saveHandlerFactory
2741
* @param ConfigInterface $sessionConfig
2842
* @param string $default
@@ -32,87 +46,100 @@ public function __construct(
3246
ConfigInterface $sessionConfig,
3347
$default = self::DEFAULT_HANDLER
3448
) {
35-
/**
36-
* Session handler
37-
*
38-
* Save handler may be set to custom value in deployment config, which will override everything else.
39-
* Otherwise, try to read PHP settings for session.save_handler value. Otherwise, use 'files' as default.
40-
*/
41-
$saveMethod = $sessionConfig->getOption('session.save_handler') ?: $default;
42-
43-
try {
44-
$this->saveHandlerAdapter = $saveHandlerFactory->create($saveMethod);
45-
} catch (SessionException $e) {
46-
$this->saveHandlerAdapter = $saveHandlerFactory->create($default);
47-
}
49+
$this->saveHandlerFactory = $saveHandlerFactory;
50+
$this->sessionConfig = $sessionConfig;
51+
$this->defaultHandler = $default;
4852
}
4953

5054
/**
51-
* Open Session - retrieve resources
55+
* Open Session - retrieve resources.
5256
*
5357
* @param string $savePath
5458
* @param string $name
5559
* @return bool
5660
*/
5761
public function open($savePath, $name)
5862
{
59-
return $this->saveHandlerAdapter->open($savePath, $name);
63+
return $this->callSafely('open', $savePath, $name);
6064
}
6165

6266
/**
63-
* Close Session - free resources
67+
* Close Session - free resources.
6468
*
6569
* @return bool
6670
*/
6771
public function close()
6872
{
69-
return $this->saveHandlerAdapter->close();
73+
return $this->callSafely('close');
7074
}
7175

7276
/**
73-
* Read session data
77+
* Read session data.
7478
*
7579
* @param string $sessionId
7680
* @return string
7781
*/
7882
public function read($sessionId)
7983
{
80-
return $this->saveHandlerAdapter->read($sessionId);
84+
return $this->callSafely('read', $sessionId);
8185
}
8286

8387
/**
84-
* Write Session - commit data to resource
88+
* Write Session - commit data to resource.
8589
*
8690
* @param string $sessionId
8791
* @param string $data
8892
* @return bool
8993
*/
9094
public function write($sessionId, $data)
9195
{
92-
return $this->saveHandlerAdapter->write($sessionId, $data);
96+
return $this->callSafely('write', $sessionId, $data);
9397
}
9498

9599
/**
96-
* Destroy Session - remove data from resource for given session id
100+
* Destroy Session - remove data from resource for given session id.
97101
*
98102
* @param string $sessionId
99103
* @return bool
100104
*/
101105
public function destroy($sessionId)
102106
{
103-
return $this->saveHandlerAdapter->destroy($sessionId);
107+
return $this->callSafely('destroy', $sessionId);
104108
}
105109

106110
/**
107-
* Garbage Collection - remove old session data older
108-
* than $maxLifetime (in seconds)
111+
* Garbage Collection - remove old session data older than $maxLifetime (in seconds).
109112
*
110113
* @param int $maxLifetime
111114
* @return bool
112115
* @SuppressWarnings(PHPMD.ShortMethodName)
113116
*/
114117
public function gc($maxLifetime)
115118
{
116-
return $this->saveHandlerAdapter->gc($maxLifetime);
119+
return $this->callSafely('gc', $maxLifetime);
120+
}
121+
122+
/**
123+
* Call save handler adapter method.
124+
*
125+
* In case custom handler failed, default files handler is used.
126+
*
127+
* @param string $method
128+
* @param mixed $arguments
129+
*
130+
* @return mixed
131+
*/
132+
private function callSafely(string $method, ...$arguments)
133+
{
134+
try {
135+
if ($this->saveHandlerAdapter === null) {
136+
$saveMethod = $this->sessionConfig->getOption('session.save_handler') ?: $this->defaultHandler;
137+
$this->saveHandlerAdapter = $this->saveHandlerFactory->create($saveMethod);
138+
}
139+
return $this->saveHandlerAdapter->{$method}(...$arguments);
140+
} catch (SessionException $exception) {
141+
$this->saveHandlerAdapter = $this->saveHandlerFactory->create($this->defaultHandler);
142+
return $this->saveHandlerAdapter->{$method}(...$arguments);
143+
}
117144
}
118145
}

0 commit comments

Comments
 (0)