generated from cloudmaker97/JTL-Plugin-Template
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBootstrap.php
More file actions
200 lines (185 loc) · 6.72 KB
/
Bootstrap.php
File metadata and controls
200 lines (185 loc) · 6.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<?php declare(strict_types=1);
/**
* @package Plugin\dh_sentry_loader
* @author Dennis Heinrich
*/
namespace Plugin\dh_sentry_loader;
use JTL\Events\Dispatcher;
use JTL\Plugin\Bootstrapper;
use JTL\Shop;
/**
* Class Bootstrap
* @package Plugin\dh_sentry_loader
*/
class Bootstrap extends Bootstrapper
{
/**
* Executed on each plugin call (e.g. on each page visit)
* @param Dispatcher $dispatcher
* @return void
*/
public function boot(Dispatcher $dispatcher): void
{
parent::boot($dispatcher);
try {
if(Shop::isFrontend()) {
$this->updateDsnAlways();
}
} catch (\Exception $e) {
Shop::Container()->getLogService()->error('Sentry-SDK: '.$e->getMessage());
}
}
/**
* Executed on plugin installation
* @return void
*/
public function installed(): void
{
parent::installed();
try {
// Add the sentry dependency
$this->composerRequireSentry();
// Add the Sentry DSN to the globalinclude.php file
$this->sentryDsnInclude();
} catch (\Exception $e) {
Shop::Container()->getLogService()->error($e->getMessage());
}
}
private function updateDsnAlways(): void
{
$sentryDsnInstalled = $this->isSentryDsnInstalled();
$sentryDsn = $this->getPlugin()->getConfig()->getValue('sentry_sdk_dsn');
// Skip if the Sentry DSN is not set
if(isset($sentryDsn) === false || empty($sentryDsn)) {
return;
}
if($sentryDsnInstalled) {
// Update the Sentry DSN in the globalinclude.php file when it is not installed
$file = file_get_contents($this->getIncludeFilePath());
if(strpos($file, $sentryDsn) === false) {
$this->updateSentryDsn($sentryDsn);
}
} else {
// Add the Sentry DSN to the globalinclude.php file if it is not installed
$this->updateSentryDsn($sentryDsn);
}
}
/**
* Executed on plugin uninstallation
* @param bool $deleteData
* @return void
*/
public function uninstalled(bool $deleteData = true): void
{
parent::uninstalled($deleteData);
try {
// Remove the sentry dependency
$this->composerRequireSentry(true);
// Remove the Sentry DSN from the globalinclude.php file
$this->sentryDsnInclude(true);
} catch (\Exception $e) {
Shop::Container()->getLogService()->error($e->getMessage());
}
}
/**
* Update the Sentry DSN in the globalinclude.php file of the shop. It
* returns false if the file does not exist or the DSN could not be updated.
* @param string $sentryDsn The Sentry DSN to update
* @return int|false The number of bytes that were written to the file or false
*/
private function updateSentryDsn(string $sentryDsn)
{
$this->removeLastLineOfSentryDsn();
$content = sprintf("try { \Sentry\init(['dsn' => '%s']); } catch(\Exception \$e) { Shop::Container()->getLogService()->error('Sentry-SDK: '.\$e->getMessage()); }", $sentryDsn);
return file_put_contents($this->getIncludeFilePath(), $content, FILE_APPEND);
}
/**
* Remove the last line of the Sentry DSN in the globalinclude.php file
* @return bool True if the last line was removed, false otherwise
*/
private function removeLastLineOfSentryDsn(): bool
{
if($this->isSentryDsnInstalled()) {
$lines = file($this->getIncludeFilePath());
$last = sizeof($lines) - 1 ;
unset($lines[$last]);
file_put_contents($this->getIncludeFilePath(), $lines);
}
return false;
}
/**
* Install or uninstall the Sentry DSN in the globalinclude.php file.
* The installation is done by writing the Sentry DSN to the globalinclude.php
*/
private function sentryDsnInclude(bool $uninstall = false)
{
$filePath = $this->getIncludeFilePath();
if($filePath !== false) {
if($uninstall) {
$this->removeLastLineOfSentryDsn();
} else {
$this->updateSentryDsn('https://localhost@localhost/0');
}
}
}
/**
* Check if the Sentry DSN is installed in the globalinclude.php file
* @return bool True if the Sentry DSN is installed in the include, false otherwise
*/
private function isSentryDsnInstalled(): bool {
$filePath = $this->getIncludeFilePath();
$searchString = "try { \Sentry\init(";
if($filePath !== false) {
$content = file_get_contents($filePath);
return strpos($content, $searchString) !== false;
} else {
return false;
}
}
/**
* Get the path of the globalinclude.php file of the shop installation.
* The path is a realpath, so it is a valid path or it returns false if the
* file does not exist. This file is called each time the shop is loaded and
* automatically includes the composer autoload.
* @return string|bool The path of the globalinclude.php file or false if it does not exist
*/
private function getIncludeFilePath(): string|bool
{
$file = 'globalinclude.php';
if(file_exists(sprintf('%s/%s', $this->getIncludeFolderPath(), $file))) {
return sprintf('%s/%s', $this->getIncludeFolderPath(), $file);
}
return false;
}
/**
* Get the includes folder of the shop installation.
* The path is a realpath, so it is a valid path or
* it returns false if the folder does not exist.
* @return string|bool
*/
private function getIncludeFolderPath(): string|bool {
$folder = __DIR__.'/../../includes';
return realpath($folder);
}
/**
* Install or uninstall the sentry/sentry composer dependency
* in the includes folder of the shop, because the plugin is not loaded in the
* early stages of the shop lifecycle. But for exception interception, the
* sentry/sentry package is needed as soon as possible to submit exceptions.
* @param bool $uninstall If true, the package will be uninstalled
* @return void
*/
private function composerRequireSentry(bool $uninstall = false): void {
if(($folder = $this->getIncludeFolderPath()) !== false) {
$output = [];
$return = -1;
// Run the composer require command
chdir($folder);
if($uninstall) {
exec('composer remove sentry/sentry', $output, $return);
} else {
exec('composer require sentry/sentry', $output, $return);
}
}
}
}