1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Backend\Modules\Pages\Actions; |
4
|
|
|
|
5
|
|
|
use Backend\Core\Engine\Authentication; |
6
|
|
|
use Backend\Core\Engine\Base\ActionEdit as BackendBaseActionEdit; |
7
|
|
|
use Backend\Core\Engine\Authentication as BackendAuthentication; |
8
|
|
|
use Backend\Core\Engine\DataGridDatabase as BackendDataGridDatabase; |
9
|
|
|
use Backend\Core\Engine\DataGridFunctions as BackendDataGridFunctions; |
10
|
|
|
use Backend\Core\Engine\Form as BackendForm; |
11
|
|
|
use Backend\Core\Language\Language as BL; |
12
|
|
|
use Backend\Core\Engine\Meta as BackendMeta; |
13
|
|
|
use Backend\Core\Engine\Model as BackendModel; |
14
|
|
|
use Backend\Form\Type\DeleteType; |
15
|
|
|
use Backend\Modules\Extensions\Engine\Model as BackendExtensionsModel; |
16
|
|
|
use Backend\Modules\Pages\Engine\Model as BackendPagesModel; |
17
|
|
|
use Backend\Modules\Search\Engine\Model as BackendSearchModel; |
18
|
|
|
use Backend\Modules\Tags\Engine\Model as BackendTagsModel; |
19
|
|
|
use Backend\Modules\Profiles\Engine\Model as BackendProfilesModel; |
20
|
|
|
use ForkCMS\Utility\Thumbnails; |
21
|
|
|
use SpoonFormHidden; |
22
|
|
|
use Symfony\Component\HttpFoundation\Response; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* This is the edit-action, it will display a form to update an item |
26
|
|
|
*/ |
27
|
|
|
class Edit extends BackendBaseActionEdit |
28
|
|
|
{ |
29
|
|
|
/** |
30
|
|
|
* The blocks linked to this page |
31
|
|
|
* |
32
|
|
|
* @var array |
33
|
|
|
*/ |
34
|
|
|
private $blocksContent = []; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* DataGrid for the drafts |
38
|
|
|
* |
39
|
|
|
* @var BackendDataGridDatabase |
40
|
|
|
*/ |
41
|
|
|
private $dgDrafts; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* The extras |
45
|
|
|
* |
46
|
|
|
* @var array |
47
|
|
|
*/ |
48
|
|
|
private $extras = []; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* The hreflang fields |
52
|
|
|
* |
53
|
|
|
* @var array |
54
|
|
|
*/ |
55
|
|
|
private $hreflangFields = []; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Is the current user a god user? |
59
|
|
|
* |
60
|
|
|
* @var bool |
61
|
|
|
*/ |
62
|
|
|
private $isGod = false; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* The positions |
66
|
|
|
* |
67
|
|
|
* @var array |
68
|
|
|
*/ |
69
|
|
|
private $positions = []; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* The template data |
73
|
|
|
* |
74
|
|
|
* @var array |
75
|
|
|
*/ |
76
|
|
|
private $templates = []; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @var string |
80
|
|
|
*/ |
81
|
|
|
private $oldUrl; |
82
|
|
|
|
83
|
|
|
public function execute(): void |
84
|
|
|
{ |
85
|
|
|
parent::execute(); |
86
|
|
|
|
87
|
|
|
// load record |
88
|
|
|
$this->loadData(); |
89
|
|
|
|
90
|
|
|
// add js |
91
|
|
|
$this->header->addJS('jstree/jquery.tree.js', null, false); |
92
|
|
|
$this->header->addJS('jstree/lib/jquery.cookie.js', null, false); |
93
|
|
|
$this->header->addJS('jstree/plugins/jquery.tree.cookie.js', null, false); |
94
|
|
|
$this->header->addJS('/js/vendors/SimpleAjaxUploader.min.js', 'Core', false, true); |
95
|
|
|
|
96
|
|
|
// get the templates |
97
|
|
|
$this->templates = BackendExtensionsModel::getTemplates(); |
98
|
|
|
|
99
|
|
|
// set the default template as checked |
100
|
|
|
$this->templates[$this->record['template_id']]['checked'] = true; |
101
|
|
|
|
102
|
|
|
// homepage? |
103
|
|
|
if ($this->id == BackendModel::HOME_PAGE_ID) { |
104
|
|
|
// loop and set disabled state |
105
|
|
|
foreach ($this->templates as &$row) { |
106
|
|
|
$row['disabled'] = ($row['has_block']); |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
// get the extras |
111
|
|
|
$this->extras = BackendExtensionsModel::getExtras(); |
112
|
|
|
|
113
|
|
|
$this->loadForm(); |
114
|
|
|
$this->loadDrafts(); |
115
|
|
|
$this->loadRevisions(); |
116
|
|
|
$this->validateForm(); |
117
|
|
|
$this->loadDeleteForm(); |
118
|
|
|
$this->parse(); |
119
|
|
|
$this->display(); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
private function loadData(): void |
123
|
|
|
{ |
124
|
|
|
// get record |
125
|
|
|
$this->id = $this->getRequest()->query->getInt('id'); |
126
|
|
|
$this->isGod = BackendAuthentication::getUser()->isGod(); |
127
|
|
|
|
128
|
|
|
// check if something went wrong |
129
|
|
|
if ($this->id === 0 || !BackendPagesModel::exists($this->id)) { |
130
|
|
|
$this->redirect( |
131
|
|
|
BackendModel::createUrlForAction('Index') . '&error=non-existing' |
132
|
|
|
); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
// get the record |
136
|
|
|
$this->record = BackendPagesModel::get($this->id); |
|
|
|
|
137
|
|
|
|
138
|
|
|
// load blocks |
139
|
|
|
$this->blocksContent = BackendPagesModel::getBlocks($this->id, $this->record['revision_id']); |
140
|
|
|
|
141
|
|
|
// is there a revision specified? |
142
|
|
|
$revisionToLoad = $this->getRequest()->query->getInt('revision'); |
143
|
|
|
|
144
|
|
|
// if this is a valid revision |
145
|
|
|
if ($revisionToLoad !== 0) { |
146
|
|
|
// overwrite the current record |
147
|
|
|
$this->record = (array) BackendPagesModel::get($this->id, $revisionToLoad); |
148
|
|
|
|
149
|
|
|
// load blocks |
150
|
|
|
$this->blocksContent = BackendPagesModel::getBlocks($this->id, $revisionToLoad); |
151
|
|
|
|
152
|
|
|
// show warning |
153
|
|
|
$this->template->assign('appendRevision', true); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
// is there a revision specified? |
157
|
|
|
$draftToLoad = $this->getRequest()->query->getInt('draft'); |
158
|
|
|
|
159
|
|
|
// if this is a valid revision |
160
|
|
|
if ($draftToLoad !== 0) { |
161
|
|
|
// overwrite the current record |
162
|
|
|
$this->record = (array) BackendPagesModel::get($this->id, $draftToLoad); |
163
|
|
|
|
164
|
|
|
// load blocks |
165
|
|
|
$this->blocksContent = BackendPagesModel::getBlocks($this->id, $draftToLoad); |
166
|
|
|
|
167
|
|
|
// show warning |
168
|
|
|
$this->template->assign('appendRevision', true); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
// reset some vars |
172
|
|
|
$this->record['full_url'] = BackendPagesModel::getFullUrl($this->record['id']); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
private function loadDrafts(): void |
176
|
|
|
{ |
177
|
|
|
// create datagrid |
178
|
|
|
$this->dgDrafts = new BackendDataGridDatabase( |
179
|
|
|
BackendPagesModel::QUERY_DATAGRID_BROWSE_SPECIFIC_DRAFTS, |
180
|
|
|
[$this->record['id'], 'draft', BL::getWorkingLanguage()] |
181
|
|
|
); |
182
|
|
|
|
183
|
|
|
// hide columns |
184
|
|
|
$this->dgDrafts->setColumnsHidden(['id', 'revision_id']); |
185
|
|
|
|
186
|
|
|
// disable paging |
187
|
|
|
$this->dgDrafts->setPaging(false); |
188
|
|
|
|
189
|
|
|
// set headers |
190
|
|
|
$this->dgDrafts->setHeaderLabels( |
191
|
|
|
[ |
192
|
|
|
'user_id' => \SpoonFilter::ucfirst(BL::lbl('By')), |
193
|
|
|
'edited_on' => \SpoonFilter::ucfirst(BL::lbl('LastEditedOn')), |
194
|
|
|
] |
195
|
|
|
); |
196
|
|
|
|
197
|
|
|
// set column-functions |
198
|
|
|
$this->dgDrafts->setColumnFunction([new BackendDataGridFunctions(), 'getUser'], ['[user_id]'], 'user_id'); |
199
|
|
|
$this->dgDrafts->setColumnFunction( |
200
|
|
|
[new BackendDataGridFunctions(), 'getTimeAgo'], |
201
|
|
|
['[edited_on]'], |
202
|
|
|
'edited_on' |
203
|
|
|
); |
204
|
|
|
$this->dgDrafts->setColumnFunction('htmlspecialchars', ['[title]'], 'title', false); |
205
|
|
|
|
206
|
|
|
// our JS needs to know an id, so we can highlight it |
207
|
|
|
$this->dgDrafts->setRowAttributes(['id' => 'row-[revision_id]']); |
208
|
|
|
|
209
|
|
|
// check if this action is allowed |
210
|
|
|
if (BackendAuthentication::isAllowedAction('Edit')) { |
211
|
|
|
// set column URLs |
212
|
|
|
$this->dgDrafts->setColumnURL( |
213
|
|
|
'title', |
214
|
|
|
BackendModel::createUrlForAction('Edit') . '&id=[id]&draft=[revision_id]' |
215
|
|
|
); |
216
|
|
|
|
217
|
|
|
// add use column |
218
|
|
|
$this->dgDrafts->addColumn( |
219
|
|
|
'use_draft', |
220
|
|
|
null, |
221
|
|
|
BL::lbl('UseThisDraft'), |
222
|
|
|
BackendModel::createUrlForAction('Edit') . '&id=[id]&draft=[revision_id]', |
223
|
|
|
BL::lbl('UseThisDraft') |
224
|
|
|
); |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
private function loadForm(): void |
229
|
|
|
{ |
230
|
|
|
// get default template id |
231
|
|
|
$defaultTemplateId = $this->get('fork.settings')->get('Pages', 'default_template', 1); |
232
|
|
|
|
233
|
|
|
// create form |
234
|
|
|
$this->form = new BackendForm('edit'); |
235
|
|
|
|
236
|
|
|
// assign in template |
237
|
|
|
$this->template->assign('defaultTemplateId', $defaultTemplateId); |
238
|
|
|
|
239
|
|
|
// create elements |
240
|
|
|
$this->form->addText('title', $this->record['title'], null, 'form-control title', 'form-control danger title'); |
241
|
|
|
$this->form->addEditor('html'); |
242
|
|
|
$this->form->addHidden('template_id', $this->record['template_id']); |
243
|
|
|
$this->form->addRadiobutton( |
244
|
|
|
'hidden', |
245
|
|
|
[ |
246
|
|
|
['label' => BL::lbl('Hidden'), 'value' => 1], |
247
|
|
|
['label' => BL::lbl('Published'), 'value' => 0], |
248
|
|
|
], |
249
|
|
|
$this->record['hidden'] |
250
|
|
|
); |
251
|
|
|
|
252
|
|
|
// image related fields |
253
|
|
|
$this->form->addImage('image')->setAttribute('data-fork-cms-role', 'image-field'); |
254
|
|
|
$this->form->addCheckbox('remove_image'); |
255
|
|
|
|
256
|
|
|
// move page fields |
257
|
|
|
$chkMovePage = $this->form->addCheckbox('move_page'); |
258
|
|
|
$chkMovePage->setAttribute('data-role', 'move-page-toggle'); |
259
|
|
|
if (!(bool) $this->record['allow_move']) { |
260
|
|
|
$chkMovePage->setAttribute('disabled'); |
261
|
|
|
$chkMovePage->setAttribute('class', 'fork-form-checkbox disabled'); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
$movePageTreeOptions = [ |
265
|
|
|
'main' => BL::lbl('MainNavigation'), |
266
|
|
|
'meta' => BL::lbl('Meta'), |
267
|
|
|
'footer' => BL::lbl('Footer'), |
268
|
|
|
'root' => BL::lbl('Root'), |
269
|
|
|
]; |
270
|
|
|
if (!BackendModel::get('fork.settings')->get('Pages', 'meta_navigation', false)) { |
271
|
|
|
unset($movePageTreeOptions['meta']); |
272
|
|
|
} |
273
|
|
|
$this->form->addDropdown( |
274
|
|
|
'move_page_tree', |
275
|
|
|
$movePageTreeOptions, |
276
|
|
|
BackendPagesModel::getTreeNameForPageId($this->id) |
277
|
|
|
)->setAttribute('data-role', 'move-page-tree-changer'); |
278
|
|
|
|
279
|
|
|
$this->form->addDropdown( |
280
|
|
|
'move_page_type', |
281
|
|
|
[ |
282
|
|
|
BackendPagesModel::TYPE_OF_DROP_BEFORE => BL::lbl('BeforePage'), |
283
|
|
|
BackendPagesModel::TYPE_OF_DROP_AFTER => BL::lbl('AfterPage'), |
284
|
|
|
BackendPagesModel::TYPE_OF_DROP_INSIDE => BL::lbl('InsidePage') |
285
|
|
|
], |
286
|
|
|
BackendPagesModel::TYPE_OF_DROP_INSIDE |
287
|
|
|
)->setAttribute('data-role', 'move-page-type-changer'); |
288
|
|
|
$dropdownPageTree = BackendPagesModel::getMoveTreeForDropdown($this->id); |
289
|
|
|
|
290
|
|
|
$ddmMovePageReferencePage = $this->form->addDropdown( |
291
|
|
|
'move_page_reference_page', |
292
|
|
|
(array) $dropdownPageTree['pages'], |
293
|
|
|
$this->record['parent_id'] != 0 ? $this->record['parent_id'] : null |
294
|
|
|
)->setDefaultElement(BL::lbl('AppendToTree'), 0)->setAttribute('data-role', 'move-page-pages-select'); |
295
|
|
|
foreach ((array) $dropdownPageTree['attributes'] as $value => $attributes) { |
296
|
|
|
$ddmMovePageReferencePage->setOptionAttributes($value, $attributes); |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
// just execute if the site is multi-language |
300
|
|
|
if ($this->getContainer()->getParameter('site.multilanguage')) { |
301
|
|
|
// loop active languages |
302
|
|
|
foreach (BL::getActiveLanguages() as $language) { |
303
|
|
|
if ($language != BL::getWorkingLanguage()) { |
304
|
|
|
$pages = BackendPagesModel::getPagesForDropdown($language); |
305
|
|
|
// add field for each language |
306
|
|
|
$field = $this->form->addDropdown('hreflang_' . $language, $pages, (!empty($this->record['data']['hreflang_' . $language]) ? $this->record['data']['hreflang_' . $language] : null))->setDefaultElement(''); |
307
|
|
|
$this->hreflangFields[$language]['field_hreflang'] = $field->parse(); |
308
|
|
|
} |
309
|
|
|
} |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
// page auth related fields |
313
|
|
|
// check if profiles module is installed |
314
|
|
|
if (BackendModel::isModuleInstalled('Profiles')) { |
315
|
|
|
// add checkbox for auth_required |
316
|
|
|
$this->form->addCheckbox( |
317
|
|
|
'auth_required', |
318
|
|
|
isset($this->record['data']['auth_required']) && $this->record['data']['auth_required'] |
319
|
|
|
); |
320
|
|
|
|
321
|
|
|
// add checkbox for index page to search |
322
|
|
|
$this->form->addCheckbox( |
323
|
|
|
'remove_from_search_index', |
324
|
|
|
isset($this->record['data']['remove_from_search_index']) && $this->record['data']['remove_from_search_index'] |
325
|
|
|
); |
326
|
|
|
|
327
|
|
|
// get all groups and parse them in key value pair |
328
|
|
|
$groupItems = BackendProfilesModel::getGroups(); |
329
|
|
|
if (!empty($groupItems)) { |
330
|
|
|
$groups = []; |
331
|
|
|
foreach ($groupItems as $key => $item) { |
332
|
|
|
$groups[] = ['label' => $item, 'value' => $key]; |
333
|
|
|
} |
334
|
|
|
// set checked values |
335
|
|
|
$checkedGroups = []; |
336
|
|
|
if (isset($this->record['data']['auth_groups']) && is_array($this->record['data']['auth_groups'])) { |
337
|
|
|
foreach ($this->record['data']['auth_groups'] as $group) { |
338
|
|
|
$checkedGroups[] = $group; |
339
|
|
|
} |
340
|
|
|
} |
341
|
|
|
// add multi checkbox |
342
|
|
|
$this->form->addMultiCheckbox('auth_groups', $groups, $checkedGroups); |
343
|
|
|
} |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
// a god user should be able to adjust the detailed settings for a page easily |
347
|
|
|
if ($this->isGod) { |
348
|
|
|
$permissions = [ |
349
|
|
|
'move' => ['data-role' => 'allow-move-toggle'], |
350
|
|
|
'children' => ['data-role' => 'allow-children-toggle'], |
351
|
|
|
'edit' => ['data-role' => 'allow-edit-toggle'], |
352
|
|
|
'delete' => ['data-role' => 'allow-delete-toggle'], |
353
|
|
|
]; |
354
|
|
|
if (BackendPagesModel::isForbiddenToMove($this->id)) { |
355
|
|
|
$permissions['move']['disabled'] = null; |
356
|
|
|
} |
357
|
|
|
if (BackendPagesModel::isForbiddenToHaveChildren($this->id)) { |
358
|
|
|
$permissions['children']['disabled'] = null; |
359
|
|
|
} |
360
|
|
|
if (BackendPagesModel::isForbiddenToDelete($this->id)) { |
361
|
|
|
$permissions['delete']['disabled'] = null; |
362
|
|
|
} |
363
|
|
|
$checked = []; |
364
|
|
|
$values = []; |
365
|
|
|
|
366
|
|
|
foreach ($permissions as $permission => $attributes) { |
367
|
|
|
$values[] = [ |
368
|
|
|
'label' => BL::msg(\SpoonFilter::toCamelCase('allow_' . $permission)), |
369
|
|
|
'value' => $permission, |
370
|
|
|
'attributes' => $attributes, |
371
|
|
|
]; |
372
|
|
|
if (isset($this->record['allow_' . $permission]) && $this->record['allow_' . $permission]) { |
373
|
|
|
$checked[] = $permission; |
374
|
|
|
} |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
$this->form->addMultiCheckbox('allow', $values, $checked); |
378
|
|
|
|
379
|
|
|
// css link class |
380
|
|
|
$page['link_class'] = $this->form->addText('link_class', isset($this->record['data']['link_class']) ? $this->record['data']['link_class'] : null); |
|
|
|
|
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
// build prototype block |
384
|
|
|
$block = []; |
385
|
|
|
$block['index'] = 0; |
386
|
|
|
$block['formElements']['chkVisible'] = $this->form->addCheckbox('block_visible_' . $block['index'], true); |
387
|
|
|
$block['formElements']['hidExtraId'] = $this->form->addHidden('block_extra_id_' . $block['index'], 0); |
388
|
|
|
$block['formElements']['hidExtraType'] = $this->form->addHidden('block_extra_type_' . $block['index'], 'rich_text'); |
389
|
|
|
$block['formElements']['hidExtraData'] = $this->form->addHidden('block_extra_data_' . $block['index']); |
390
|
|
|
$block['formElements']['hidPosition'] = $this->form->addHidden('block_position_' . $block['index'], 'fallback'); |
391
|
|
|
$block['formElements']['txtHTML'] = $this->form->addTextarea( |
392
|
|
|
'block_html_' . $block['index'], |
393
|
|
|
'' |
394
|
|
|
); // this is no editor; we'll add the editor in JS |
395
|
|
|
|
396
|
|
|
// add default block to "fallback" position, the only one which we can rest assured to exist |
397
|
|
|
$this->positions['fallback']['blocks'][] = $block; |
398
|
|
|
|
399
|
|
|
// content has been submitted: re-create submitted content rather than the database-fetched content |
400
|
|
|
if ($this->getRequest()->request->has('block_html_0')) { |
401
|
|
|
$this->blocksContent = []; |
402
|
|
|
$hasBlock = false; |
403
|
|
|
$i = 1; |
404
|
|
|
|
405
|
|
|
// loop submitted blocks |
406
|
|
|
$positions = []; |
407
|
|
|
while ($this->getRequest()->request->has('block_position_' . $i)) { |
408
|
|
|
$block = []; |
409
|
|
|
|
410
|
|
|
// save block position |
411
|
|
|
$block['position'] = $this->getRequest()->request->get('block_position_' . $i); |
412
|
|
|
$positions[$block['position']][] = $block; |
413
|
|
|
|
414
|
|
|
// set linked extra |
415
|
|
|
$block['extra_id'] = $this->getRequest()->request->get('block_extra_id_' . $i); |
416
|
|
|
$block['extra_type'] = $this->getRequest()->request->get('block_extra_type_' . $i); |
417
|
|
|
$block['extra_data'] = $this->getRequest()->request->get('block_extra_data_' . $i); |
418
|
|
|
|
419
|
|
|
// reset some stuff |
420
|
|
|
if ($block['extra_id'] <= 0) { |
421
|
|
|
$block['extra_id'] = null; |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
// init html |
425
|
|
|
$block['html'] = null; |
426
|
|
|
|
427
|
|
|
$html = $this->getRequest()->request->get('block_html_' . $i); |
428
|
|
|
|
429
|
|
|
// extra-type is HTML |
430
|
|
|
if ($block['extra_id'] === null || $block['extra_type'] == 'usertemplate') { |
431
|
|
|
if ($this->getRequest()->request->get('block_extra_type_' . $i) === 'usertemplate') { |
432
|
|
|
$block['extra_id'] = $this->getRequest()->request->get('block_extra_id_' . $i); |
433
|
|
|
$_POST['block_extra_data_' . $i] = htmlspecialchars($_POST['block_extra_data_' . $i]); |
434
|
|
|
} else { |
435
|
|
|
// reset vars |
436
|
|
|
$block['extra_id'] = null; |
437
|
|
|
} |
438
|
|
|
$block['html'] = $html; |
439
|
|
|
} else { |
440
|
|
|
// type of block |
441
|
|
|
if (isset($this->extras[$block['extra_id']]['type']) && $this->extras[$block['extra_id']]['type'] == 'block') { |
442
|
|
|
// set error |
443
|
|
|
if ($hasBlock) { |
444
|
|
|
$this->form->addError(BL::err('CantAdd2Blocks')); |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
// home can't have blocks |
448
|
|
|
if ($this->record['id'] == BackendModel::HOME_PAGE_ID) { |
449
|
|
|
$this->form->addError(BL::err('HomeCantHaveBlocks')); |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
// reset var |
453
|
|
|
$hasBlock = true; |
454
|
|
|
} |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
// set data |
458
|
|
|
$block['created_on'] = BackendModel::getUTCDate(); |
459
|
|
|
$block['edited_on'] = $block['created_on']; |
460
|
|
|
$block['visible'] = $this->getRequest()->request->getBoolean('block_visible_' . $i); |
461
|
|
|
$block['sequence'] = count($positions[$block['position']]) - 1; |
462
|
|
|
|
463
|
|
|
// add to blocks |
464
|
|
|
$this->blocksContent[] = $block; |
465
|
|
|
|
466
|
|
|
// increment counter; go fetch next block |
467
|
|
|
++$i; |
468
|
|
|
} |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
// build blocks array |
472
|
|
|
foreach ($this->blocksContent as $i => $block) { |
473
|
|
|
$block['index'] = $i + 1; |
474
|
|
|
$block['formElements']['chkVisible'] = $this->form->addCheckbox( |
475
|
|
|
'block_visible_' . $block['index'], |
476
|
|
|
$block['visible'] |
477
|
|
|
); |
478
|
|
|
$block['formElements']['hidExtraId'] = $this->form->addHidden( |
479
|
|
|
'block_extra_id_' . $block['index'], |
480
|
|
|
(int) $block['extra_id'] |
481
|
|
|
); |
482
|
|
|
$block['formElements']['hidExtraType'] = $this->form->addHidden( |
483
|
|
|
'block_extra_type_' . $block['index'], |
484
|
|
|
$block['extra_type'] |
485
|
|
|
); |
486
|
|
|
$this->form->add( |
487
|
|
|
$this->getHiddenJsonField( |
488
|
|
|
'block_extra_data_' . $block['index'], |
489
|
|
|
$block['extra_data'] |
490
|
|
|
) |
491
|
|
|
); |
492
|
|
|
$block['formElements']['hidExtraData'] = $this->form->getField('block_extra_data_' . $block['index']); |
493
|
|
|
$block['formElements']['hidPosition'] = $this->form->addHidden( |
494
|
|
|
'block_position_' . $block['index'], |
495
|
|
|
$block['position'] |
496
|
|
|
); |
497
|
|
|
$block['formElements']['txtHTML'] = $this->form->addTextarea( |
498
|
|
|
'block_html_' . $block['index'], |
499
|
|
|
$block['html'] |
500
|
|
|
); // this is no editor; we'll add the editor in JS |
501
|
|
|
|
502
|
|
|
$this->positions[$block['position']]['blocks'][] = $block; |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
// redirect |
506
|
|
|
$redirectValue = 'none'; |
507
|
|
|
if (isset($this->record['data']['internal_redirect']['page_id'])) { |
508
|
|
|
$redirectValue = 'internal'; |
509
|
|
|
} |
510
|
|
|
if (isset($this->record['data']['external_redirect']['url'])) { |
511
|
|
|
$redirectValue = 'external'; |
512
|
|
|
} |
513
|
|
|
$redirectValues = [ |
514
|
|
|
['value' => 'none', 'label' => \SpoonFilter::ucfirst(BL::lbl('None'))], |
515
|
|
|
[ |
516
|
|
|
'value' => 'internal', |
517
|
|
|
'label' => \SpoonFilter::ucfirst(BL::lbl('InternalLink')), |
518
|
|
|
'variables' => ['isInternal' => true], |
519
|
|
|
], |
520
|
|
|
[ |
521
|
|
|
'value' => 'external', |
522
|
|
|
'label' => \SpoonFilter::ucfirst(BL::lbl('ExternalLink')), |
523
|
|
|
'variables' => ['isExternal' => true], |
524
|
|
|
], |
525
|
|
|
]; |
526
|
|
|
$this->form->addRadiobutton('redirect', $redirectValues, $redirectValue); |
527
|
|
|
$this->form->addDropdown( |
528
|
|
|
'internal_redirect', |
529
|
|
|
BackendPagesModel::getPagesForDropdown(), |
530
|
|
|
($redirectValue == 'internal') ? $this->record['data']['internal_redirect']['page_id'] : null |
531
|
|
|
); |
532
|
|
|
$this->form->addText( |
533
|
|
|
'external_redirect', |
534
|
|
|
($redirectValue == 'external') ? urldecode($this->record['data']['external_redirect']['url']) : null, |
535
|
|
|
null, |
536
|
|
|
null, |
537
|
|
|
null, |
538
|
|
|
true |
539
|
|
|
); |
540
|
|
|
|
541
|
|
|
// page info |
542
|
|
|
$this->form->addCheckbox('navigation_title_overwrite', $this->record['navigation_title_overwrite']); |
543
|
|
|
$this->form->addText('navigation_title', $this->record['navigation_title']); |
544
|
|
|
|
545
|
|
|
if ($this->userCanSeeAndEditTags()) { |
546
|
|
|
// tags |
547
|
|
|
$this->form->addText( |
548
|
|
|
'tags', |
549
|
|
|
BackendTagsModel::getTags($this->url->getModule(), $this->id), |
|
|
|
|
550
|
|
|
null, |
551
|
|
|
'form-control js-tags-input', |
552
|
|
|
'error js-tags-input' |
553
|
|
|
)->setAttribute('aria-describedby', 'tags-info'); |
554
|
|
|
} |
555
|
|
|
|
556
|
|
|
// a specific action |
557
|
|
|
$isAction = isset($this->record['data']['is_action']) && $this->record['data']['is_action']; |
558
|
|
|
$this->form->addCheckbox('is_action', $isAction); |
559
|
|
|
|
560
|
|
|
// extra |
561
|
|
|
$blockTypes = BackendPagesModel::getTypes(); |
562
|
|
|
$this->form->addDropdown('extra_type', $blockTypes, key($blockTypes)); |
563
|
|
|
|
564
|
|
|
// meta |
565
|
|
|
$this->meta = new BackendMeta($this->form, $this->record['meta_id'], 'title', true); |
|
|
|
|
566
|
|
|
$this->oldUrl = $this->meta->getUrl(); |
567
|
|
|
|
568
|
|
|
// set callback for generating an unique URL |
569
|
|
|
$this->meta->setUrlCallback( |
570
|
|
|
'Backend\Modules\Pages\Engine\Model', |
571
|
|
|
'getUrl', |
572
|
|
|
[$this->record['id'], $this->record['parent_id'], $isAction] |
573
|
|
|
); |
574
|
|
|
} |
575
|
|
|
|
576
|
|
|
private function loadRevisions(): void |
577
|
|
|
{ |
578
|
|
|
// create datagrid |
579
|
|
|
$this->dgRevisions = new BackendDataGridDatabase( |
580
|
|
|
BackendPagesModel::QUERY_BROWSE_REVISIONS, |
581
|
|
|
[ |
582
|
|
|
$this->id, |
583
|
|
|
'archive', |
584
|
|
|
BL::getWorkingLanguage( |
585
|
|
|
), |
586
|
|
|
] |
587
|
|
|
); |
588
|
|
|
|
589
|
|
|
// hide columns |
590
|
|
|
$this->dgRevisions->setColumnsHidden(['id', 'revision_id']); |
591
|
|
|
|
592
|
|
|
// disable paging |
593
|
|
|
$this->dgRevisions->setPaging(false); |
594
|
|
|
|
595
|
|
|
// set headers |
596
|
|
|
$this->dgRevisions->setHeaderLabels( |
597
|
|
|
[ |
598
|
|
|
'user_id' => \SpoonFilter::ucfirst(BL::lbl('By')), |
599
|
|
|
'edited_on' => \SpoonFilter::ucfirst(BL::lbl('LastEditedOn')), |
600
|
|
|
] |
601
|
|
|
); |
602
|
|
|
|
603
|
|
|
// set functions |
604
|
|
|
$this->dgRevisions->setColumnFunction( |
605
|
|
|
[new BackendDataGridFunctions(), 'getUser'], |
606
|
|
|
['[user_id]'], |
607
|
|
|
'user_id' |
608
|
|
|
); |
609
|
|
|
$this->dgRevisions->setColumnFunction( |
610
|
|
|
[new BackendDataGridFunctions(), 'getTimeAgo'], |
611
|
|
|
['[edited_on]'], |
612
|
|
|
'edited_on' |
613
|
|
|
); |
614
|
|
|
$this->dgRevisions->setColumnFunction('htmlspecialchars', ['[title]'], 'title', false); |
615
|
|
|
|
616
|
|
|
// check if this action is allowed |
617
|
|
|
if (BackendAuthentication::isAllowedAction('Edit')) { |
618
|
|
|
// set column URLs |
619
|
|
|
$this->dgRevisions->setColumnURL( |
620
|
|
|
'title', |
621
|
|
|
BackendModel::createUrlForAction('Edit') . '&id=[id]&revision=[revision_id]' |
622
|
|
|
); |
623
|
|
|
|
624
|
|
|
// add use column |
625
|
|
|
$this->dgRevisions->addColumn( |
626
|
|
|
'use_revision', |
627
|
|
|
null, |
628
|
|
|
BL::lbl('UseThisVersion'), |
629
|
|
|
BackendModel::createUrlForAction('Edit') . '&id=[id]&revision=[revision_id]', |
630
|
|
|
BL::lbl('UseThisVersion') |
631
|
|
|
); |
632
|
|
|
} |
633
|
|
|
} |
634
|
|
|
|
635
|
|
|
protected function parse(): void |
636
|
|
|
{ |
637
|
|
|
parent::parse(); |
638
|
|
|
|
639
|
|
|
// set |
640
|
|
|
$this->record['url'] = $this->meta->getUrl(); |
641
|
|
|
if ($this->id == 1) { |
642
|
|
|
$this->record['url'] = ''; |
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
// parse some variables |
646
|
|
|
$this->template->assign('item', $this->record); |
647
|
|
|
$this->template->assign('isGod', $this->isGod); |
648
|
|
|
$this->template->assign('templates', $this->templates); |
649
|
|
|
$this->template->assign('positions', $this->positions); |
650
|
|
|
$this->template->assign('extrasData', json_encode(BackendModel::recursiveHtmlspecialchars(BackendExtensionsModel::getExtrasData()))); |
651
|
|
|
$this->template->assign('extrasById', json_encode($this->extras)); |
652
|
|
|
$this->template->assign('prefixURL', rtrim(BackendPagesModel::getFullUrl($this->record['parent_id']), '/')); |
653
|
|
|
$this->template->assign('formErrors', (string) $this->form->getErrors()); |
654
|
|
|
$this->template->assign('showTags', $this->userCanSeeAndEditTags()); |
655
|
|
|
$this->template->assign('hreflangFields', $this->hreflangFields); |
656
|
|
|
$this->header->appendDetailToBreadcrumbs($this->record['title']); |
657
|
|
|
|
658
|
|
|
// init var |
659
|
|
|
$showDelete = true; |
660
|
|
|
|
661
|
|
|
// has children? |
662
|
|
|
if (BackendPagesModel::getFirstChildId($this->record['id']) !== false) { |
663
|
|
|
$showDelete = false; |
664
|
|
|
} |
665
|
|
|
if (!$this->record['delete_allowed']) { |
666
|
|
|
$showDelete = false; |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
// allowed? |
670
|
|
|
if (!BackendAuthentication::isAllowedAction('Delete', $this->getModule())) { |
671
|
|
|
$showDelete = false; |
672
|
|
|
} |
673
|
|
|
|
674
|
|
|
// show delete button |
675
|
|
|
$this->template->assign('allowPagesDelete', $showDelete); |
676
|
|
|
|
677
|
|
|
// assign template |
678
|
|
|
$this->template->assignArray($this->templates[$this->record['template_id']], 'template'); |
679
|
|
|
|
680
|
|
|
// parse datagrids |
681
|
|
|
$this->template->assign( |
682
|
|
|
'revisions', |
683
|
|
|
($this->dgRevisions->getNumResults() != 0) ? $this->dgRevisions->getContent() : false |
684
|
|
|
); |
685
|
|
|
$this->template->assign('drafts', ($this->dgDrafts->getNumResults() != 0) ? $this->dgDrafts->getContent() : false); |
686
|
|
|
|
687
|
|
|
// parse the tree |
688
|
|
|
$this->template->assign('tree', BackendPagesModel::getTreeHTML()); |
689
|
|
|
|
690
|
|
|
// assign if profiles module is installed |
691
|
|
|
$this->template->assign('showAuthenticationTab', BackendModel::isModuleInstalled('Profiles')); |
692
|
|
|
|
693
|
|
|
$this->header->addJsData( |
694
|
|
|
'pages', |
695
|
|
|
'userTemplates', |
696
|
|
|
BackendPagesModel::loadUserTemplates() |
697
|
|
|
); |
698
|
|
|
} |
699
|
|
|
|
700
|
|
|
private function validateForm(): void |
701
|
|
|
{ |
702
|
|
|
if (!$this->form->isSubmitted()) { |
703
|
|
|
return; |
704
|
|
|
} |
705
|
|
|
|
706
|
|
|
$status = $this->getRequest()->request->get('status'); |
707
|
|
|
if (!in_array($status, ['active', 'draft'], true)) { |
708
|
|
|
$status = 'active'; |
709
|
|
|
} |
710
|
|
|
|
711
|
|
|
$redirectValue = $this->form->getField('redirect')->getValue(); |
712
|
|
|
if ($redirectValue === 'internal') { |
713
|
|
|
$this->form->getField('internal_redirect')->isFilled( |
714
|
|
|
BL::err('FieldIsRequired') |
715
|
|
|
); |
716
|
|
|
} |
717
|
|
|
if ($redirectValue === 'external') { |
718
|
|
|
$this->form->getField('external_redirect')->isURL(BL::err('InvalidURL')); |
719
|
|
|
} |
720
|
|
|
|
721
|
|
|
// set callback for generating an unique URL |
722
|
|
|
$this->meta->setUrlCallback( |
723
|
|
|
BackendPagesModel::class, |
724
|
|
|
'getUrl', |
725
|
|
|
[$this->record['id'], $this->record['parent_id'], $this->form->getField('is_action')->getChecked()] |
726
|
|
|
); |
727
|
|
|
|
728
|
|
|
$this->form->cleanupFields(); |
729
|
|
|
$this->form->getField('title')->isFilled(BL::err('TitleIsRequired')); |
730
|
|
|
if ($this->form->getField('navigation_title_overwrite')->isChecked()) { |
731
|
|
|
$this->form->getField('navigation_title')->isFilled(BL::err('FieldIsRequired')); |
732
|
|
|
} |
733
|
|
|
$this->meta->validate(); |
734
|
|
|
|
735
|
|
|
if ($this->form->getField('move_page')->isChecked()) { |
736
|
|
|
$this->form->getField('move_page_tree')->isFilled(BL::err('FieldIsRequired')); |
737
|
|
|
$this->form->getField('move_page_type')->isFilled(BL::err('FieldIsRequired')); |
738
|
|
|
$this->form->getField('move_page_reference_page')->isFilled(BL::err('FieldIsRequired')); |
739
|
|
|
} |
740
|
|
|
|
741
|
|
|
if (!$this->form->isCorrect()) { |
742
|
|
|
return; |
743
|
|
|
} |
744
|
|
|
|
745
|
|
|
$data = $this->buildPageData($redirectValue); |
746
|
|
|
|
747
|
|
|
$page = [ |
748
|
|
|
'id' => $this->record['id'], |
749
|
|
|
'user_id' => BackendAuthentication::getUser()->getUserId(), |
750
|
|
|
'parent_id' => $this->record['parent_id'], |
751
|
|
|
'template_id' => (int) $this->form->getField('template_id')->getValue(), |
752
|
|
|
'meta_id' => $this->meta->save(), |
753
|
|
|
'language' => BL::getWorkingLanguage(), |
754
|
|
|
'type' => $this->record['type'], |
755
|
|
|
'title' => $this->form->getField('title')->getValue(), |
756
|
|
|
'navigation_title' => !empty($this->form->getField('navigation_title')->getValue()) |
757
|
|
|
? $this->form->getField('navigation_title')->getValue() : $this->form->getField('title')->getValue(), |
758
|
|
|
'navigation_title_overwrite' => $this->form->getField('navigation_title_overwrite')->isChecked(), |
759
|
|
|
'hidden' => $this->form->getField('hidden')->getValue(), |
760
|
|
|
'status' => $status, |
761
|
|
|
'publish_on' => BackendModel::getUTCDate(null, $this->record['publish_on']), |
762
|
|
|
'created_on' => BackendModel::getUTCDate(null, $this->record['created_on']), |
763
|
|
|
'edited_on' => BackendModel::getUTCDate(), |
764
|
|
|
'allow_move' => $this->record['allow_move'], |
765
|
|
|
'allow_children' => $this->record['allow_children'], |
766
|
|
|
'allow_edit' => $this->record['allow_edit'], |
767
|
|
|
'allow_delete' => $this->record['allow_delete'], |
768
|
|
|
'sequence' => $this->record['sequence'], |
769
|
|
|
'data' => serialize($data), |
770
|
|
|
]; |
771
|
|
|
|
772
|
|
|
$page = $this->changePagePermissions($page); |
773
|
|
|
|
774
|
|
|
if (empty($page['navigation_title'])) { |
775
|
|
|
$page['navigation_title'] = $page['title']; |
776
|
|
|
} |
777
|
|
|
|
778
|
|
|
// update page, store the revision id, we need it when building the blocks |
779
|
|
|
$page['revision_id'] = BackendPagesModel::update($page); |
780
|
|
|
|
781
|
|
|
$this->insertBlocks($page['revision_id']); |
782
|
|
|
|
783
|
|
|
$this->saveTags($page['id']); |
784
|
|
|
|
785
|
|
|
$cacheShouldBeUpdated = !( |
786
|
|
|
$this->record['title'] === $page['title'] |
787
|
|
|
&& $this->record['navigation_title'] === $page['navigation_title'] |
788
|
|
|
&& $this->record['navigation_title_overwrite'] == $page['navigation_title_overwrite'] // can be 0 or false |
789
|
|
|
&& $this->record['hidden'] == $page['hidden'] // can be 0 or false |
790
|
|
|
&& $this->meta->getUrl() === $this->oldUrl |
791
|
|
|
); |
792
|
|
|
|
793
|
|
|
// build cache |
794
|
|
|
if ($cacheShouldBeUpdated) { |
795
|
|
|
BackendPagesModel::buildCache(BL::getWorkingLanguage()); |
796
|
|
|
} |
797
|
|
|
|
798
|
|
|
if ($page['status'] === 'draft') { |
799
|
|
|
$this->redirect( |
800
|
|
|
BackendModel::createUrlForAction('Edit') . '&id=' . $page['id'] |
801
|
|
|
. '&report=saved-as-draft&var=' . rawurlencode($page['title']) . '&highlight=row-' . $page['id'] |
802
|
|
|
. '&draft=' . $page['revision_id'] |
803
|
|
|
); |
804
|
|
|
|
805
|
|
|
return; |
806
|
|
|
} |
807
|
|
|
|
808
|
|
|
$this->movePage($page); |
809
|
|
|
$this->saveSearchIndex($data['remove_from_search_index'] || $redirectValue !== 'none', $page); |
810
|
|
|
|
811
|
|
|
$this->redirect( |
812
|
|
|
BackendModel::createUrlForAction('Edit') . '&id=' . $page['id'] . '&report=edited&var=' |
813
|
|
|
. rawurlencode($page['title']) . '&highlight=row-' . $page['id'] |
814
|
|
|
); |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
private function changePagePermissions(array $page): array |
818
|
|
|
{ |
819
|
|
|
if (!$this->isGod) { |
820
|
|
|
return $page; |
821
|
|
|
} |
822
|
|
|
|
823
|
|
|
$page['allow_move'] = BackendPagesModel::isForbiddenToMove($this->id) ? false : in_array( |
824
|
|
|
'move', |
825
|
|
|
(array) $this->form->getField('allow')->getValue(), |
826
|
|
|
true |
827
|
|
|
); |
828
|
|
|
$page['allow_children'] = BackendPagesModel::isForbiddenToHaveChildren($this->id) ? false : in_array( |
829
|
|
|
'children', |
830
|
|
|
(array) $this->form->getField('allow')->getValue(), |
831
|
|
|
true |
832
|
|
|
); |
833
|
|
|
$page['allow_edit'] = in_array( |
834
|
|
|
'edit', |
835
|
|
|
(array) $this->form->getField('allow')->getValue(), |
836
|
|
|
true |
837
|
|
|
); |
838
|
|
|
$page['allow_delete'] = BackendPagesModel::isForbiddenToDelete($this->id) ? false : in_array( |
839
|
|
|
'delete', |
840
|
|
|
(array) $this->form->getField('allow')->getValue(), |
841
|
|
|
true |
842
|
|
|
); |
843
|
|
|
|
844
|
|
|
return $page; |
845
|
|
|
} |
846
|
|
|
|
847
|
|
|
private function movePage(array $page): void |
848
|
|
|
{ |
849
|
|
|
if (!$page['allow_move'] || !$this->form->getField('move_page')->isChecked()) { |
850
|
|
|
return; |
851
|
|
|
} |
852
|
|
|
|
853
|
|
|
BackendPagesModel::move( |
854
|
|
|
$page['id'], |
855
|
|
|
(int) $this->form->getField('move_page_reference_page')->getValue(), |
856
|
|
|
$this->form->getField('move_page_type')->getValue(), |
857
|
|
|
$this->form->getField('move_page_tree')->getValue() |
858
|
|
|
); |
859
|
|
|
BackendPagesModel::buildCache(BL::getWorkingLanguage()); |
860
|
|
|
} |
861
|
|
|
|
862
|
|
|
private function buildPageData(string $redirectValue): array |
863
|
|
|
{ |
864
|
|
|
$data = []; |
865
|
|
|
$templateId = (int) $this->form->getField('template_id')->getValue(); |
866
|
|
|
|
867
|
|
|
if ($this->form->getField('is_action')->isChecked()) { |
868
|
|
|
$data['is_action'] = true; |
869
|
|
|
} |
870
|
|
|
if ($redirectValue === 'internal') { |
871
|
|
|
$data['internal_redirect'] = [ |
872
|
|
|
'page_id' => $this->form->getField('internal_redirect')->getValue(), |
873
|
|
|
'code' => Response::HTTP_TEMPORARY_REDIRECT, |
874
|
|
|
]; |
875
|
|
|
} |
876
|
|
|
if ($redirectValue === 'external') { |
877
|
|
|
$data['external_redirect'] = [ |
878
|
|
|
'url' => BackendPagesModel::getEncodedRedirectUrl( |
879
|
|
|
$this->form->getField('external_redirect')->getValue() |
880
|
|
|
), |
881
|
|
|
'code' => Response::HTTP_TEMPORARY_REDIRECT, |
882
|
|
|
]; |
883
|
|
|
} |
884
|
|
|
if (array_key_exists('image', $this->templates[$templateId]['data'])) { |
885
|
|
|
$data['image'] = $this->getImage($this->templates[$templateId]['data']['image']); |
886
|
|
|
} |
887
|
|
|
|
888
|
|
|
$data['auth_required'] = false; |
889
|
|
|
if (BackendModel::isModuleInstalled('Profiles') && $this->form->getField('auth_required')->isChecked()) { |
890
|
|
|
$data['auth_required'] = true; |
891
|
|
|
// get all groups and parse them in key value pair |
892
|
|
|
$groupItems = BackendProfilesModel::getGroups(); |
893
|
|
|
|
894
|
|
|
if (!empty($groupItems)) { |
895
|
|
|
$data['auth_groups'] = $this->form->getField('auth_groups')->getValue(); |
896
|
|
|
} |
897
|
|
|
} |
898
|
|
|
|
899
|
|
|
$data['remove_from_search_index'] = false; |
900
|
|
|
if (BackendModel::isModuleInstalled('Profiles') |
901
|
|
|
&& $this->form->getField('remove_from_search_index')->isChecked() |
902
|
|
|
&& $this->form->getField('auth_required')->isChecked()) { |
903
|
|
|
$data['remove_from_search_index'] = true; |
904
|
|
|
} |
905
|
|
|
|
906
|
|
|
// just execute if the site is multi-language |
907
|
|
|
if ($this->getContainer()->getParameter('site.multilanguage')) { |
908
|
|
|
// loop active languages |
909
|
|
|
foreach (BL::getActiveLanguages() as $language) { |
910
|
|
|
if ($language != BL::getWorkingLanguage() |
911
|
|
|
&& $this->form->getfield('hreflang_' . $language)->isFilled()) { |
912
|
|
|
$data['hreflang_' . $language] = $this->form->getfield('hreflang_' . $language)->getValue(); |
913
|
|
|
} |
914
|
|
|
} |
915
|
|
|
} |
916
|
|
|
|
917
|
|
|
// link class |
918
|
|
|
$data['link_class'] = $this->record['data']['link_class'] ?? null; |
919
|
|
|
if ($this->isGod) { |
920
|
|
|
$data['link_class'] = $this->form->getField('link_class')->getValue(); |
921
|
|
|
} |
922
|
|
|
|
923
|
|
|
return $data; |
924
|
|
|
} |
925
|
|
|
|
926
|
|
|
private function insertBlocks(int $revisionId): void |
927
|
|
|
{ |
928
|
|
|
$possiblePositions = $this->templates[$this->form->getField('template_id')->getValue()]['data']['names']; |
929
|
|
|
foreach ($this->blocksContent as $i => $block) { |
930
|
|
|
$this->blocksContent[$i]['revision_id'] = $revisionId; |
931
|
|
|
|
932
|
|
|
// validate blocks, only save blocks for valid positions |
933
|
|
|
if (!in_array($block['position'], $possiblePositions, true)) { |
934
|
|
|
unset($this->blocksContent[$i]); |
935
|
|
|
} |
936
|
|
|
} |
937
|
|
|
|
938
|
|
|
BackendPagesModel::insertBlocks($this->blocksContent); |
939
|
|
|
} |
940
|
|
|
|
941
|
|
|
private function saveTags(int $pageId): void |
942
|
|
|
{ |
943
|
|
|
if (!$this->userCanSeeAndEditTags()) { |
944
|
|
|
return; |
945
|
|
|
} |
946
|
|
|
|
947
|
|
|
BackendTagsModel::saveTags( |
948
|
|
|
$pageId, |
949
|
|
|
$this->form->getField('tags')->getValue(), |
950
|
|
|
$this->url->getModule() |
951
|
|
|
); |
952
|
|
|
} |
953
|
|
|
|
954
|
|
|
private function saveSearchIndex(bool $removeFromSearchIndex, array $page): void |
955
|
|
|
{ |
956
|
|
|
if ($removeFromSearchIndex) { |
957
|
|
|
BackendSearchModel::removeIndex( |
958
|
|
|
$this->getModule(), |
959
|
|
|
$page['id'] |
960
|
|
|
); |
961
|
|
|
|
962
|
|
|
return; |
963
|
|
|
} |
964
|
|
|
|
965
|
|
|
$searchText = ''; |
966
|
|
|
foreach ($this->blocksContent as $block) { |
967
|
|
|
$searchText .= ' ' . $block['html']; |
968
|
|
|
} |
969
|
|
|
|
970
|
|
|
BackendSearchModel::saveIndex( |
971
|
|
|
$this->getModule(), |
972
|
|
|
$page['id'], |
973
|
|
|
['title' => $page['title'], 'text' => $searchText] |
974
|
|
|
); |
975
|
|
|
} |
976
|
|
|
|
977
|
|
|
private function getImage(bool $allowImage): ?string |
978
|
|
|
{ |
979
|
|
|
$imageFilename = array_key_exists('image', (array) $this->record['data']) ? $this->record['data']['image'] : null; |
980
|
|
|
|
981
|
|
|
if (!$this->form->getField('image')->isFilled() && !$this->form->getField('remove_image')->isChecked()) { |
982
|
|
|
return $imageFilename; |
983
|
|
|
} |
984
|
|
|
|
985
|
|
|
$imagePath = FRONTEND_FILES_PATH . '/Pages/images'; |
986
|
|
|
|
987
|
|
|
// delete the current image |
988
|
|
|
$this->get(Thumbnails::class)->delete($imagePath, (string) $imageFilename); |
989
|
|
|
|
990
|
|
|
if (!$allowImage |
991
|
|
|
|| ($this->form->getField('remove_image')->isChecked() && !$this->form->getField('image')->isFilled()) |
992
|
|
|
) { |
993
|
|
|
return null; |
994
|
|
|
} |
995
|
|
|
|
996
|
|
|
$imageFilename = $this->meta->getUrl() . '_' . time() . '.' . $this->form->getField('image')->getExtension(); |
997
|
|
|
$this->form->getField('image')->generateThumbnails($imagePath, $imageFilename); |
998
|
|
|
|
999
|
|
|
return $imageFilename; |
1000
|
|
|
} |
1001
|
|
|
|
1002
|
|
|
private function userCanSeeAndEditTags(): bool |
1003
|
|
|
{ |
1004
|
|
|
return Authentication::isAllowedAction('Edit', 'Tags') && Authentication::isAllowedAction('GetAllTags', 'Tags'); |
1005
|
|
|
} |
1006
|
|
|
|
1007
|
|
|
private function loadDeleteForm(): void |
1008
|
|
|
{ |
1009
|
|
|
$deleteForm = $this->createForm( |
1010
|
|
|
DeleteType::class, |
1011
|
|
|
['id' => $this->record['id']], |
1012
|
|
|
['module' => $this->getModule()] |
1013
|
|
|
); |
1014
|
|
|
$this->template->assign('deleteForm', $deleteForm->createView()); |
1015
|
|
|
} |
1016
|
|
|
|
1017
|
|
|
private function getHiddenJsonField(string $name, ?string $json): SpoonFormHidden |
1018
|
|
|
{ |
1019
|
|
|
return new class($name, htmlspecialchars($json)) extends SpoonFormHidden { |
|
|
|
|
1020
|
|
|
public function getValue($allowHTML = null) |
1021
|
|
|
{ |
1022
|
|
|
return parent::getValue(true); |
1023
|
|
|
} |
1024
|
|
|
}; |
1025
|
|
|
} |
1026
|
|
|
} |
1027
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.