1
|
|
|
<?php |
2
|
|
|
namespace Mouf\Utils\Patcher\Controllers; |
3
|
|
|
|
4
|
|
|
use Mouf\Controllers\AbstractMoufInstanceController; |
5
|
|
|
|
6
|
|
|
use Mouf\Database\TDBM\Utils\TDBMDaoGenerator; |
7
|
|
|
|
8
|
|
|
use Mouf\Html\Widgets\MessageService\Service\UserMessageInterface; |
9
|
|
|
use Mouf\MoufManager; |
10
|
|
|
|
11
|
|
|
use Mouf\Mvc\Splash\Controllers\Controller; |
12
|
|
|
|
13
|
|
|
use Mouf\Reflection\MoufReflectionProxy; |
14
|
|
|
|
15
|
|
|
use Mouf\Html\HtmlElement\HtmlBlock; |
16
|
|
|
use Mouf\InstanceProxy; |
17
|
|
|
use Mouf\Utils\Patcher\PatchException; |
18
|
|
|
use Mouf\Utils\Patcher\PatchInterface; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* The controller to track which patchs have been applied. |
22
|
|
|
|
23
|
|
|
*/ |
24
|
|
|
class PatchController extends AbstractMoufInstanceController { |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* |
28
|
|
|
* @var HtmlBlock |
29
|
|
|
*/ |
30
|
|
|
public $content; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* A list of patches returned by the getView method of the PatchService. |
34
|
|
|
* @var array |
35
|
|
|
*/ |
36
|
|
|
protected $patchesArray; |
37
|
|
|
|
38
|
|
|
protected $nbAwaiting = 0; |
39
|
|
|
protected $nbError = 0; |
40
|
|
|
|
41
|
|
|
protected $nbPatchesByType = []; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Page listing the patches to be applied. |
45
|
|
|
* |
46
|
|
|
* @Action |
47
|
|
|
* @Logged |
48
|
|
|
*/ |
49
|
|
|
public function defaultAction($name, $selfedit="false") { |
50
|
|
|
$this->initController($name, $selfedit); |
51
|
|
|
|
52
|
|
|
$patchService = new InstanceProxy($name, $selfedit == "true"); |
53
|
|
|
$this->patchesArray = $patchService->getView(); |
54
|
|
|
|
55
|
|
|
foreach ($this->patchesArray as $patch) { |
56
|
|
|
if ($patch['status'] == PatchInterface::STATUS_AWAITING) { |
57
|
|
|
$this->nbAwaiting++; |
58
|
|
|
} elseif ($patch['status'] == PatchInterface::STATUS_ERROR) { |
59
|
|
|
$this->nbError++; |
60
|
|
|
} |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
$this->content->addFile(__DIR__."/../../../../views/patchesList.php", $this); |
64
|
|
|
$this->template->toHtml(); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Runs a patch. |
70
|
|
|
* |
71
|
|
|
* @Action |
72
|
|
|
* @Logged |
73
|
|
|
* @param string $name |
74
|
|
|
* @param string $uniqueName |
75
|
|
|
* @param string $action |
76
|
|
|
*/ |
77
|
|
|
public function runPatch($name, $uniqueName, $action, $selfedit) { |
78
|
|
|
|
79
|
|
|
$patchService = new InstanceProxy($name, $selfedit == "true"); |
80
|
|
|
|
81
|
|
|
try { |
82
|
|
|
|
83
|
|
|
if ($action == 'apply') { |
84
|
|
|
$this->patchesArray = $patchService->apply($uniqueName); |
85
|
|
|
} else if ($action == 'revert') { |
86
|
|
|
$this->patchesArray = $patchService->revert($uniqueName); |
87
|
|
|
} else if ($action == 'skip') { |
88
|
|
|
$this->patchesArray = $patchService->skip($uniqueName); |
89
|
|
|
} else { |
90
|
|
|
throw new PatchException("Unknown action: '".$action."'"); |
91
|
|
|
} |
92
|
|
|
} catch (\Exception $e) { |
93
|
|
|
$htmlMessage = "An error occured while applying the patch: ".$e->getMessage(); |
94
|
|
|
set_user_message($htmlMessage); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
header('Location: .?name='.urlencode($name)); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Displays the page to select the patch types to be applied. |
102
|
|
|
* |
103
|
|
|
* @Action |
104
|
|
|
* @Logged |
105
|
|
|
* @param string $name |
106
|
|
|
* @param string $selfedit |
107
|
|
|
*/ |
108
|
|
|
public function runAllPatches($name, $selfedit) { |
109
|
|
|
$this->initController($name, $selfedit); |
110
|
|
|
|
111
|
|
|
$patchService = new InstanceProxy($name, $selfedit == "true"); |
112
|
|
|
$this->patchesArray = $patchService->getView(); |
113
|
|
|
|
114
|
|
|
$types = $patchService->_getSerializedTypes(); |
115
|
|
|
|
116
|
|
|
foreach ($types as $type) { |
117
|
|
|
$this->nbPatchesByType[$type['name']] = 0; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
$nbNoneDefaultPatches = 0; |
121
|
|
|
|
122
|
|
|
foreach ($this->patchesArray as $patch) { |
123
|
|
|
if ($patch['status'] == PatchInterface::STATUS_AWAITING || $patch['status'] == PatchInterface::STATUS_ERROR) { |
124
|
|
|
$type = $patch['patch_type']; |
125
|
|
|
if ($type !== '') { |
126
|
|
|
$nbNoneDefaultPatches++; |
127
|
|
|
} |
128
|
|
|
$this->nbPatchesByType[$type]++; |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
// If all patches to be applied are default patches, let's do this right now. |
133
|
|
|
if ($nbNoneDefaultPatches === 0) { |
134
|
|
|
$this->applyAllPatches($name, [''], $selfedit); |
135
|
|
|
return; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
ksort($this->nbPatchesByType); |
139
|
|
|
|
140
|
|
|
// Otherwise, let's display a screen to select the patch types to be applied. |
141
|
|
|
$this->content->addFile(__DIR__."/../../../../views/applyPatches.php", $this); |
142
|
|
|
$this->template->toHtml(); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* Runs all patches in a row. |
148
|
|
|
* |
149
|
|
|
* @Action |
150
|
|
|
* @Logged |
151
|
|
|
* @param string $name |
152
|
|
|
* @param array $types |
153
|
|
|
* @param string $selfedit |
154
|
|
|
*/ |
155
|
|
|
public function applyAllPatches($name, array $types, $selfedit) { |
156
|
|
|
$patchService = new InstanceProxy($name, $selfedit == "true"); |
157
|
|
|
$this->patchesArray = $patchService->getView(); |
158
|
|
|
|
159
|
|
|
// Array of cound of applied and skip patched. Key is the patch type. |
160
|
|
|
$appliedPatchArray = []; |
161
|
|
|
$skippedPatchArray = []; |
162
|
|
|
|
163
|
|
|
try { |
164
|
|
|
foreach ($this->patchesArray as $patch) { |
165
|
|
|
if ($patch['status'] == PatchInterface::STATUS_AWAITING || $patch['status'] == PatchInterface::STATUS_ERROR) { |
166
|
|
|
$type = $patch['patch_type']; |
167
|
|
|
if (in_array($type, $types) || $type === '') { |
168
|
|
|
$patchService->apply($patch['uniqueName']); |
169
|
|
|
if (!isset($appliedPatchArray[$type])) { |
170
|
|
|
$appliedPatchArray[$type] = 0; |
171
|
|
|
} |
172
|
|
|
$appliedPatchArray[$type]++; |
173
|
|
|
} else { |
174
|
|
|
$patchService->skip($patch['uniqueName']); |
175
|
|
|
if (!isset($skippedPatchArray[$type])) { |
176
|
|
|
$skippedPatchArray[$type] = 0; |
177
|
|
|
} |
178
|
|
|
$skippedPatchArray[$type]++; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
} catch (\Exception $e) { |
184
|
|
|
$htmlMessage = "An error occured while applying the patch: ".$e->getMessage(); |
185
|
|
|
set_user_message($htmlMessage); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
$this->displayNotificationMessage($appliedPatchArray, $skippedPatchArray); |
189
|
|
|
|
190
|
|
|
header('Location: .?name='.urlencode($name)); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
private function displayNotificationMessage(array $appliedPatchArray, array $skippedPatchArray) |
194
|
|
|
{ |
195
|
|
|
$nbPatchesApplied = array_sum($appliedPatchArray); |
196
|
|
|
$nbPatchesSkipped = array_sum($skippedPatchArray); |
197
|
|
|
$msg = ''; |
198
|
|
View Code Duplication |
if ($nbPatchesApplied !== 0) { |
|
|
|
|
199
|
|
|
$patchArr = []; |
200
|
|
|
foreach ($appliedPatchArray as $name => $number) { |
201
|
|
|
$name = $name ?: 'default'; |
202
|
|
|
$patchArr[] = plainstring_to_htmlprotected($name).': '.$number; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
$msg .= sprintf('%d patch(es) applied (%s)', $nbPatchesApplied, implode(', ', $patchArr)); |
206
|
|
|
} |
207
|
|
View Code Duplication |
if ($nbPatchesSkipped !== 0) { |
|
|
|
|
208
|
|
|
$patchArr = []; |
209
|
|
|
foreach ($skippedPatchArray as $name => $number) { |
210
|
|
|
$name = $name ?: 'default'; |
211
|
|
|
$patchArr[] = plainstring_to_htmlprotected($name).': '.$number; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
$msg .= sprintf('%d patch(es) skipped (%s)', $nbPatchesSkipped, implode(', ', $patchArr)); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
if ($msg !== '') { |
218
|
|
|
set_user_message($msg, UserMessageInterface::SUCCESS); |
219
|
|
|
} |
220
|
|
|
} |
221
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.