Skip to content

Commit d0dc1d4

Browse files
committed
Add static resource app
1 parent b891938 commit d0dc1d4

File tree

2 files changed

+163
-1
lines changed

2 files changed

+163
-1
lines changed

App/Application.php renamed to App/Http.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
use Magento\Framework\ObjectManagerInterface;
2424
use Magento\Framework\Registry;
2525

26-
class Application implements AppInterface
26+
class Http implements AppInterface
2727
{
2828
public function __construct(
2929
private ObjectManagerInterface $objectManager,

App/StaticResource.php

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<?php
2+
/**
3+
* Copyright © OpenGento, All rights reserved.
4+
* See LICENSE bundled with this library for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Opengento\Application\App;
9+
10+
use Exception;
11+
use InvalidArgumentException;
12+
use Magento\Framework\App\Bootstrap;
13+
use Magento\Framework\App\DeploymentConfig;
14+
use Magento\Framework\App\Filesystem\DirectoryList;
15+
use Magento\Framework\App\Request\Http;
16+
use Magento\Framework\App\Response\FileInterface;
17+
use Magento\Framework\App\ResponseInterface;
18+
use Magento\Framework\App\State;
19+
use Magento\Framework\App\View\Asset\Publisher;
20+
use Magento\Framework\AppInterface;
21+
use Magento\Framework\Config\ConfigOptionsListConstants;
22+
use Magento\Framework\Debug;
23+
use Magento\Framework\Filesystem\Proxy as FilesystemProxy;
24+
use Magento\Framework\Filesystem\Driver\File;
25+
use Magento\Framework\Module\ModuleList;
26+
use Magento\Framework\Profiler;
27+
use Magento\Framework\Validator\Locale;
28+
use Magento\Framework\View\Asset\Repository;
29+
use Magento\Framework\View\Design\Theme\ThemePackageList;
30+
use Psr\Log\LoggerInterface;
31+
32+
class StaticResource implements AppInterface
33+
{
34+
public function __construct(
35+
private State $state,
36+
private FileInterface $response,
37+
private Http $request,
38+
private Publisher $publisher,
39+
private Repository $assetRepo,
40+
private ModuleList $moduleList,
41+
private DeploymentConfig $deploymentConfig,
42+
private File $driver,
43+
private ThemePackageList $themePackageList,
44+
private Locale $localeValidator,
45+
private LoggerInterface $logger,
46+
private FilesystemProxy $filesystem
47+
) {}
48+
49+
/**
50+
* Finds requested resource and provides it to the client
51+
*
52+
* @throws Exception
53+
*/
54+
public function launch(): ResponseInterface
55+
{
56+
// disabling profiling when retrieving static resource
57+
Profiler::reset();
58+
$appMode = $this->state->getMode();
59+
if ($appMode === State::MODE_PRODUCTION
60+
&& !$this->deploymentConfig->getConfigData(
61+
ConfigOptionsListConstants::CONFIG_PATH_SCD_ON_DEMAND_IN_PRODUCTION
62+
)
63+
) {
64+
$this->response->setHttpResponseCode(404);
65+
return $this->response;
66+
}
67+
68+
$path = $this->request->get('resource');
69+
try {
70+
$params = $this->parsePath($path ?? '');
71+
} catch (InvalidArgumentException $e) {
72+
if ($appMode === State::MODE_PRODUCTION) {
73+
$this->response->setHttpResponseCode(404);
74+
return $this->response;
75+
}
76+
throw $e;
77+
}
78+
79+
if (!($this->isThemeAllowed($params['area'] . DIRECTORY_SEPARATOR . $params['theme'])
80+
&& $this->localeValidator->isValid($params['locale']))
81+
) {
82+
if ($appMode === State::MODE_PRODUCTION) {
83+
$this->response->setHttpResponseCode(404);
84+
return $this->response;
85+
}
86+
throw new InvalidArgumentException('Requested path ' . $path . ' is wrong.');
87+
}
88+
89+
$file = $params['file'];
90+
unset($params['file']);
91+
$asset = $this->assetRepo->createAsset($file, $params);
92+
$this->response->setFilePath($asset->getSourceFile());
93+
$this->publisher->publish($asset);
94+
95+
return $this->response;
96+
}
97+
98+
/**
99+
* @inheritdoc
100+
*/
101+
public function catchException(Bootstrap $bootstrap, Exception $exception): bool
102+
{
103+
$this->logger->critical($exception->getMessage());
104+
if ($bootstrap->isDeveloperMode()) {
105+
$this->response->setHttpResponseCode(404);
106+
$this->response->setHeader('Content-Type', 'text/plain');
107+
$this->response->setBody(
108+
$exception->getMessage() . "\n" .
109+
Debug::trace(
110+
$exception->getTrace(),
111+
true,
112+
true,
113+
(bool)getenv('MAGE_DEBUG_SHOW_ARGS')
114+
)
115+
);
116+
$this->response->sendResponse();
117+
} else {
118+
require $this->filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/404.php');
119+
}
120+
121+
return true;
122+
}
123+
124+
/**
125+
* Parse path to identify parts needed for searching original file
126+
*
127+
* @throws InvalidArgumentException
128+
*/
129+
protected function parsePath(string $path): array
130+
{
131+
$path = ltrim($path, '/');
132+
$safePath = $this->driver->getRealPathSafety($path);
133+
$parts = explode('/', $safePath, 6);
134+
if (count($parts) < 5) {
135+
// Checking that path contains all required parts and is not above static folder.
136+
throw new InvalidArgumentException("Requested path '$path' is wrong.");
137+
}
138+
139+
$result = [];
140+
$result['area'] = $parts[0];
141+
$result['theme'] = $parts[1] . '/' . $parts[2];
142+
$result['locale'] = $parts[3];
143+
if (count($parts) >= 6 && $this->moduleList->has($parts[4])) {
144+
$result['module'] = $parts[4];
145+
} else {
146+
$result['module'] = '';
147+
if (isset($parts[5])) {
148+
$parts[5] = $parts[4] . '/' . $parts[5];
149+
} else {
150+
$parts[5] = $parts[4];
151+
}
152+
}
153+
$result['file'] = $parts[5];
154+
155+
return $result;
156+
}
157+
158+
private function isThemeAllowed(string $theme): bool
159+
{
160+
return array_key_exists($theme, $this->themePackageList->getThemes());
161+
}
162+
}

0 commit comments

Comments
 (0)