Skip to content

Commit 28633a7

Browse files
authored
Merge pull request #65 from dachcom-digital/datatype
introduce release type
2 parents f8209cd + 17db06c commit 28633a7

16 files changed

+240
-41
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ The last SEO Bundle for pimcore you'll ever need!
3535

3636
```json
3737
"require" : {
38-
"dachcom-digital/seo" : "~3.0.0",
38+
"dachcom-digital/seo" : "~3.1.0",
3939
}
4040
```
4141

UPGRADE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Upgrade Notes
22

3+
## 3.1.0
4+
- **[NEW FEATURE]** Add Release Type to allow draft/public states [@64](https://github.com/dachcom-digital/pimcore-seo/issues/64)
5+
36
## 3.0.3
47
- Fix Symfony Console deprecation in QueuedIndexDataCommand [@NiklasBr](https://github.com/dachcom-digital/pimcore-seo/pull/63)
58

config/doctrine/model/ElementMetaData.orm.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ SeoBundle\Model\ElementMetaData:
2424
column: data
2525
nullable: false
2626
type: array
27+
releaseType:
28+
column: release_type
29+
nullable: false
30+
type: string
31+
options:
32+
default: 'public'
2733
uniqueConstraints:
2834
element_type_id_integrator:
29-
columns: [element_type, element_id, integrator]
35+
columns: [element_type, element_id, integrator, release_type]

public/js/metaData/abstractMetaDataPanel.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Seo.MetaData.AbstractMetaDataPanel = Class.create({
55
element: null,
66
integrator: [],
77

8+
draftNode: null,
89
layout: null,
910
tabPanel: null,
1011
renderAsTab: false,
@@ -67,7 +68,24 @@ Seo.MetaData.AbstractMetaDataPanel = Class.create({
6768
return;
6869
}
6970

71+
this.draftNode = new Ext.form.FieldContainer({
72+
xtype: 'container',
73+
flex: 1,
74+
hidden: resp.isDraft === false,
75+
html: t('seo_bundle.panel.draft_note'),
76+
style: {
77+
padding: '5px',
78+
border: '1px solid #6428b4',
79+
background: '#6428b45c',
80+
margin: '0 0 10px 0',
81+
color: 'black'
82+
}
83+
});
84+
85+
this.layout.insert(0, this.draftNode)
86+
7087
this.buildMetaDataIntegrator(resp.data, resp.configuration, resp.availableLocales);
88+
7189
}.bind(this),
7290
failure: function () {
7391
Ext.Msg.alert(t('error'), t('seo_bundle.panel.error_fetch_data'));
@@ -99,14 +117,17 @@ Seo.MetaData.AbstractMetaDataPanel = Class.create({
99117
}
100118
},
101119

102-
save: function () {
120+
save: function (task) {
103121

104122
var integratorValues = this.getIntegratorValues();
105123

124+
this.draftNode.setHidden(task === 'publish');
125+
106126
Ext.Ajax.request({
107127
url: '/admin/seo/meta-data/set-element-meta-data-configuration',
108128
method: 'POST',
109129
params: {
130+
task: task,
110131
integratorValues: Ext.encode(integratorValues),
111132
elementType: this.getElementType(),
112133
elementId: this.getElementId()

public/js/plugin.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,25 @@ class SeoCore {
6262

6363
const document = ev.detail.document;
6464

65-
if (ev.detail.task === 'autoSave' || ev.detail.task === 'version') {
65+
if (ev.detail.task === 'autoSave') {
6666
return;
6767
}
6868

6969
if (document.hasOwnProperty('seoPanel')) {
70-
document.seoPanel.save();
70+
document.seoPanel.save(ev.detail.task);
7171
}
7272
}
7373

7474
postSaveObject(ev) {
7575

7676
const object = ev.detail.object;
7777

78-
if (ev.detail.task === 'autoSave' || ev.detail.task === 'version') {
78+
if (ev.detail.task === 'autoSave') {
7979
return;
8080
}
8181

8282
if (object.hasOwnProperty('seoPanel')) {
83-
object.seoPanel.save();
83+
object.seoPanel.save(ev.detail.task);
8484
}
8585
}
8686

src/Controller/Admin/MetaDataController.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Pimcore\Model\Document;
77
use Pimcore\Bundle\AdminBundle\Controller\AdminAbstractController;
88
use SeoBundle\Manager\ElementMetaDataManagerInterface;
9+
use SeoBundle\Model\ElementMetaDataInterface;
910
use SeoBundle\Tool\LocaleProviderInterface;
1011
use Symfony\Component\HttpFoundation\JsonResponse;
1112
use Symfony\Component\HttpFoundation\Request;
@@ -45,14 +46,18 @@ public function getElementMetaDataConfigurationAction(Request $request): JsonRes
4546
}
4647

4748
$configuration = $this->elementMetaDataManager->getMetaDataIntegratorBackendConfiguration($element);
48-
$data = $this->elementMetaDataManager->getElementDataForBackend($elementType, $elementId);
49-
50-
return $this->adminJson([
51-
'success' => true,
52-
'data' => $data,
53-
'availableLocales' => $availableLocales,
54-
'configuration' => $configuration,
55-
]);
49+
$elementBackendData = $this->elementMetaDataManager->getElementDataForBackend($elementType, $elementId);
50+
51+
return $this->adminJson(
52+
array_merge(
53+
[
54+
'success' => true,
55+
'availableLocales' => $availableLocales,
56+
'configuration' => $configuration,
57+
],
58+
$elementBackendData
59+
)
60+
);
5661
}
5762

5863
/**
@@ -62,6 +67,7 @@ public function setElementMetaDataConfigurationAction(Request $request): JsonRes
6267
{
6368
$elementId = (int) $request->request->get('elementId', 0);
6469
$elementType = $request->request->get('elementType');
70+
$task = $request->request->get('task', 'publish');
6571
$integratorValues = json_decode($request->request->get('integratorValues'), true, 512, JSON_THROW_ON_ERROR);
6672

6773
if (!is_array($integratorValues)) {
@@ -70,7 +76,8 @@ public function setElementMetaDataConfigurationAction(Request $request): JsonRes
7076

7177
foreach ($integratorValues as $integratorName => $integratorData) {
7278
$sanitizedData = is_array($integratorData) ? $integratorData : [];
73-
$this->elementMetaDataManager->saveElementData($elementType, $elementId, $integratorName, $sanitizedData);
79+
$releaseType = $task === 'publish' ? ElementMetaDataInterface::RELEASE_TYPE_PUBLIC : ElementMetaDataInterface::RELEASE_TYPE_DRAFT;
80+
$this->elementMetaDataManager->saveElementData($elementType, $elementId, $integratorName, $sanitizedData, false, $releaseType);
7481
}
7582

7683
return $this->adminJson([

src/EventListener/ElementMetaDataListener.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ public static function getSubscribedEvents(): array
2525

2626
public function handleDocumentDeletion(DocumentEvent $event): void
2727
{
28-
$this->elementMetaDataManager->deleteElementData('document', $event->getDocument()->getId());
28+
$this->elementMetaDataManager->deleteElementData('document', $event->getDocument()->getId(), null);
2929
}
3030

3131
public function handleObjectDeletion(DataObjectEvent $event): void
3232
{
33-
$this->elementMetaDataManager->deleteElementData('object', $event->getObject()->getId());
33+
$this->elementMetaDataManager->deleteElementData('object', $event->getObject()->getId(), null);
3434
}
3535
}

src/Manager/ElementMetaDataManager.php

Lines changed: 100 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,44 @@ public function getMetaDataIntegratorBackendConfiguration(mixed $correspondingEl
4141
return $configuration;
4242
}
4343

44-
public function getElementData(string $elementType, int $elementId): array
44+
public function getElementData(string $elementType, int $elementId, bool $allowDraftReleaseType = false): array
4545
{
46-
$elementValues = $this->elementMetaDataRepository->findAll($elementType, $elementId);
46+
$fetchingReleaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC;
47+
if ($allowDraftReleaseType === true && $this->elementMetaDataExistsWithReleaseType($elementType, $elementId, ElementMetaDataInterface::RELEASE_TYPE_DRAFT)) {
48+
$fetchingReleaseType = ElementMetaDataInterface::RELEASE_TYPE_DRAFT;
49+
}
50+
51+
$elementValues = $this->elementMetaDataRepository->findAll($elementType, $elementId, $fetchingReleaseType);
4752

4853
// BC Reason: If old document metadata is available, use it!
4954
// @todo: make this decision configurable? We don't need this within fresh installations!
5055

51-
return $this->checkForLegacyData($elementValues, $elementType, $elementId);
56+
return $this->checkForLegacyData($elementValues, $elementType, $elementId, $fetchingReleaseType);
5257
}
5358

5459
public function getElementDataForBackend(string $elementType, int $elementId): array
5560
{
61+
$isDraft = false;
5662
$parsedData = [];
57-
$data = $this->getElementData($elementType, $elementId);
63+
$data = $this->getElementData($elementType, $elementId, true);
5864

5965
foreach ($data as $element) {
66+
67+
if ($element->getReleaseType() === ElementMetaDataInterface::RELEASE_TYPE_DRAFT) {
68+
$isDraft = true;
69+
}
70+
6071
$metaDataIntegrator = $this->metaDataIntegratorRegistry->get($element->getIntegrator());
6172
$parsedData[$element->getIntegrator()] = $metaDataIntegrator->validateBeforeBackend($elementType, $elementId, $element->getData());
6273
}
6374

6475
// BC Reason: If old document metadata is available, use it!
6576
// @todo: make this decision configurable? We don't need this within fresh installations!
6677

67-
return $this->checkForLegacyBackendData($parsedData, $elementType, $elementId);
78+
return [
79+
'isDraft' => $isDraft,
80+
'data' => $this->checkForLegacyBackendData($parsedData, $elementType, $elementId)
81+
];
6882
}
6983

7084
public function getElementDataForXliffExport(string $elementType, int $elementId, string $locale): array
@@ -114,22 +128,46 @@ public function saveElementDataFromXliffImport(string $elementType, int $element
114128
}
115129
}
116130

117-
public function saveElementData(string $elementType, int $elementId, string $integratorName, array $data, bool $merge = false): void
118-
{
119-
$elementMetaData = $this->elementMetaDataRepository->findByIntegrator($elementType, $elementId, $integratorName);
131+
public function saveElementData(
132+
string $elementType,
133+
int $elementId,
134+
string $integratorName,
135+
array $data,
136+
bool $merge = false,
137+
string $releaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC
138+
): void {
139+
140+
$elementMetaData = $this->determinateElementMetaEntity($elementType, $elementId, $integratorName, $releaseType);
120141

121142
if (!$elementMetaData instanceof ElementMetaDataInterface) {
122143
$elementMetaData = new ElementMetaData();
123144
$elementMetaData->setElementType($elementType);
124145
$elementMetaData->setElementId($elementId);
125146
$elementMetaData->setIntegrator($integratorName);
147+
$elementMetaData->setReleaseType($releaseType);
126148
}
127149

128150
$metaDataIntegrator = $this->metaDataIntegratorRegistry->get($integratorName);
129151
$sanitizedData = $metaDataIntegrator->validateBeforePersist($elementType, $elementId, $data, $elementMetaData->getData(), $merge);
130152

131153
// remove empty meta data
132154
if ($sanitizedData === null) {
155+
156+
if ($releaseType === ElementMetaDataInterface::RELEASE_TYPE_DRAFT) {
157+
158+
// if draft, we still persist an empty element
159+
// to determinate reset when publish state is incoming
160+
161+
if (
162+
$elementMetaData->getId() > 0 ||
163+
$this->elementMetaDataExistsWithReleaseType($elementType, $elementId, ElementMetaDataInterface::RELEASE_TYPE_PUBLIC, $integratorName)
164+
) {
165+
$this->persistElementMetaData($elementMetaData, []);
166+
}
167+
168+
return;
169+
}
170+
133171
if ($elementMetaData->getId() > 0) {
134172
$this->entityManager->remove($elementMetaData);
135173
$this->entityManager->flush();
@@ -138,8 +176,12 @@ public function saveElementData(string $elementType, int $elementId, string $int
138176
return;
139177
}
140178

141-
$elementMetaData->setData($sanitizedData);
179+
$this->persistElementMetaData($elementMetaData, $sanitizedData);
180+
}
142181

182+
private function persistElementMetaData(ElementMetaDataInterface $elementMetaData, array $data): void
183+
{
184+
$elementMetaData->setData($data);
143185
$this->entityManager->persist($elementMetaData);
144186
$this->entityManager->flush();
145187
}
@@ -157,9 +199,9 @@ public function generatePreviewDataForElement(string $elementType, int $elementI
157199
return $metaDataIntegrator->getPreviewParameter($element, $template, $data);
158200
}
159201

160-
public function deleteElementData(string $elementType, int $elementId): void
202+
public function deleteElementData(string $elementType, int $elementId, ?string $releaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC): void
161203
{
162-
$elementData = $this->elementMetaDataRepository->findAll($elementType, $elementId);
204+
$elementData = $this->elementMetaDataRepository->findAll($elementType, $elementId, $releaseType);
163205

164206
if (count($elementData) === 0) {
165207
return;
@@ -175,7 +217,7 @@ public function deleteElementData(string $elementType, int $elementId): void
175217
/**
176218
* @return array<int, ElementMetaDataInterface>
177219
*/
178-
protected function checkForLegacyData(array $elements, string $elementType, int $elementId): array
220+
protected function checkForLegacyData(array $elements, string $elementType, int $elementId, string $releaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC): array
179221
{
180222
// as soon we have configured seo elements,
181223
// we'll never check the document again. It's all about performance.
@@ -197,6 +239,7 @@ protected function checkForLegacyData(array $elements, string $elementType, int
197239
$legacyTitleDescription->setElementType($elementType);
198240
$legacyTitleDescription->setElementId($elementId);
199241
$legacyTitleDescription->setIntegrator('title_description');
242+
$legacyTitleDescription->setReleaseType($releaseType);
200243
$legacyTitleDescription->setData(['title' => $legacyData['title'], 'description' => $legacyData['description']]);
201244
$elements[] = $legacyTitleDescription;
202245
}
@@ -264,4 +307,49 @@ protected function getDocumentLegacyData(int $documentId): ?array
264307
'hasTitleDescriptionIntegrator' => $hasTitleDescriptionIntegrator !== false
265308
];
266309
}
310+
311+
private function determinateElementMetaEntity(
312+
string $elementType,
313+
int $elementId,
314+
string $integratorName,
315+
string $releaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC
316+
): ?ElementMetaDataInterface {
317+
318+
$hasDraft = $this->elementMetaDataExistsWithReleaseType($elementType, $elementId, ElementMetaDataInterface::RELEASE_TYPE_DRAFT);
319+
320+
if ($releaseType === ElementMetaDataInterface::RELEASE_TYPE_PUBLIC && $hasDraft === true) {
321+
322+
// delete draft
323+
$this->deleteElementData($elementType, $elementId, ElementMetaDataInterface::RELEASE_TYPE_DRAFT);
324+
325+
return $this->elementMetaDataRepository->findByIntegrator($elementType, $elementId, $integratorName, $releaseType);
326+
}
327+
328+
return $this->elementMetaDataRepository->findByIntegrator($elementType, $elementId, $integratorName, $releaseType);
329+
}
330+
331+
private function elementMetaDataExistsWithReleaseType(string $elementType, int $elementId, string $releaseType, ?string $integratorName = null): bool
332+
{
333+
$qb = $this->elementMetaDataRepository->getQueryBuilder();
334+
335+
$qb
336+
->select('COUNT(e.id)')
337+
->andWhere('e.elementType = :elementType')
338+
->andWhere('e.elementId = :elementId')
339+
->andWhere('e.releaseType = :releaseType')
340+
->setParameter('elementType', $elementType)
341+
->setParameter('elementId', $elementId)
342+
->setParameter('releaseType', $releaseType);
343+
344+
if ($integratorName !== null) {
345+
$qb
346+
->andWhere('e.integrator = :integratorName')
347+
->setParameter('integratorName', $integratorName);
348+
}
349+
350+
return $qb
351+
->getQuery()
352+
->getSingleScalarResult() > 0;
353+
}
354+
267355
}

0 commit comments

Comments
 (0)