Skip to content

Commit

Permalink
introduce release type
Browse files Browse the repository at this point in the history
  • Loading branch information
solverat committed Aug 9, 2024
1 parent f8209cd commit 949231f
Show file tree
Hide file tree
Showing 15 changed files with 211 additions and 39 deletions.
3 changes: 3 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Upgrade Notes

## 3.1.0
- **[NEW FEATURE]** Add Release Type to allow draft/public states [@64](https://github.com/dachcom-digital/pimcore-seo/issues/64)

## 3.0.3
- Fix Symfony Console deprecation in QueuedIndexDataCommand [@NiklasBr](https://github.com/dachcom-digital/pimcore-seo/pull/63)

Expand Down
8 changes: 7 additions & 1 deletion config/doctrine/model/ElementMetaData.orm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ SeoBundle\Model\ElementMetaData:
column: data
nullable: false
type: array
releaseType:
column: release_type
nullable: false
type: string
options:
default: 'public'
uniqueConstraints:
element_type_id_integrator:
columns: [element_type, element_id, integrator]
columns: [element_type, element_id, integrator, release_type]
23 changes: 22 additions & 1 deletion public/js/metaData/abstractMetaDataPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Seo.MetaData.AbstractMetaDataPanel = Class.create({
element: null,
integrator: [],

draftNode: null,
layout: null,
tabPanel: null,
renderAsTab: false,
Expand Down Expand Up @@ -67,7 +68,24 @@ Seo.MetaData.AbstractMetaDataPanel = Class.create({
return;
}

this.draftNode = new Ext.form.FieldContainer({
xtype: 'container',
flex: 1,
hidden: resp.isDraft === false,
html: t('seo_bundle.panel.draft_note'),
style: {
padding: '5px',
border: '1px solid #6428b4',
background: '#6428b45c',
margin: '0 0 10px 0',
color: 'black'
}
});

this.layout.insert(0, this.draftNode)

this.buildMetaDataIntegrator(resp.data, resp.configuration, resp.availableLocales);

}.bind(this),
failure: function () {
Ext.Msg.alert(t('error'), t('seo_bundle.panel.error_fetch_data'));
Expand Down Expand Up @@ -99,14 +117,17 @@ Seo.MetaData.AbstractMetaDataPanel = Class.create({
}
},

save: function () {
save: function (task) {

var integratorValues = this.getIntegratorValues();

this.draftNode.setHidden(task === 'publish');

Ext.Ajax.request({
url: '/admin/seo/meta-data/set-element-meta-data-configuration',
method: 'POST',
params: {
task: task,
integratorValues: Ext.encode(integratorValues),
elementType: this.getElementType(),
elementId: this.getElementId()
Expand Down
8 changes: 4 additions & 4 deletions public/js/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,25 @@ class SeoCore {

const document = ev.detail.document;

if (ev.detail.task === 'autoSave' || ev.detail.task === 'version') {
if (ev.detail.task === 'autoSave') {
return;
}

if (document.hasOwnProperty('seoPanel')) {
document.seoPanel.save();
document.seoPanel.save(ev.detail.task);
}
}

postSaveObject(ev) {

const object = ev.detail.object;

if (ev.detail.task === 'autoSave' || ev.detail.task === 'version') {
if (ev.detail.task === 'autoSave') {
return;
}

if (object.hasOwnProperty('seoPanel')) {
object.seoPanel.save();
object.seoPanel.save(ev.detail.task);
}
}

Expand Down
25 changes: 16 additions & 9 deletions src/Controller/Admin/MetaDataController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Pimcore\Model\Document;
use Pimcore\Bundle\AdminBundle\Controller\AdminAbstractController;
use SeoBundle\Manager\ElementMetaDataManagerInterface;
use SeoBundle\Model\ElementMetaDataInterface;
use SeoBundle\Tool\LocaleProviderInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
Expand Down Expand Up @@ -45,14 +46,18 @@ public function getElementMetaDataConfigurationAction(Request $request): JsonRes
}

$configuration = $this->elementMetaDataManager->getMetaDataIntegratorBackendConfiguration($element);
$data = $this->elementMetaDataManager->getElementDataForBackend($elementType, $elementId);

return $this->adminJson([
'success' => true,
'data' => $data,
'availableLocales' => $availableLocales,
'configuration' => $configuration,
]);
$elementBackendData = $this->elementMetaDataManager->getElementDataForBackend($elementType, $elementId);

return $this->adminJson(
array_merge(
[
'success' => true,
'availableLocales' => $availableLocales,
'configuration' => $configuration,
],
$elementBackendData
)
);
}

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

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

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

return $this->adminJson([
Expand Down
4 changes: 2 additions & 2 deletions src/EventListener/ElementMetaDataListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ public static function getSubscribedEvents(): array

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

public function handleObjectDeletion(DataObjectEvent $event): void
{
$this->elementMetaDataManager->deleteElementData('object', $event->getObject()->getId());
$this->elementMetaDataManager->deleteElementData('object', $event->getObject()->getId(), null);
}
}
81 changes: 70 additions & 11 deletions src/Manager/ElementMetaDataManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,30 +41,44 @@ public function getMetaDataIntegratorBackendConfiguration(mixed $correspondingEl
return $configuration;
}

public function getElementData(string $elementType, int $elementId): array
public function getElementData(string $elementType, int $elementId, bool $allowDraftReleaseType = false): array
{
$elementValues = $this->elementMetaDataRepository->findAll($elementType, $elementId);
$fetchingReleaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC;
if ($allowDraftReleaseType === true && $this->elementMetaDataExistsWithReleaseType($elementType, $elementId, ElementMetaDataInterface::RELEASE_TYPE_DRAFT)) {
$fetchingReleaseType = ElementMetaDataInterface::RELEASE_TYPE_DRAFT;
}

$elementValues = $this->elementMetaDataRepository->findAll($elementType, $elementId, $fetchingReleaseType);

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

return $this->checkForLegacyData($elementValues, $elementType, $elementId);
return $this->checkForLegacyData($elementValues, $elementType, $elementId, $fetchingReleaseType);
}

public function getElementDataForBackend(string $elementType, int $elementId): array
{
$isDraft = false;
$parsedData = [];
$data = $this->getElementData($elementType, $elementId);
$data = $this->getElementData($elementType, $elementId, true);

foreach ($data as $element) {

if ($element->getReleaseType() === ElementMetaDataInterface::RELEASE_TYPE_DRAFT) {
$isDraft = true;
}

$metaDataIntegrator = $this->metaDataIntegratorRegistry->get($element->getIntegrator());
$parsedData[$element->getIntegrator()] = $metaDataIntegrator->validateBeforeBackend($elementType, $elementId, $element->getData());
}

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

return $this->checkForLegacyBackendData($parsedData, $elementType, $elementId);
return [
'isDraft' => $isDraft,
'data' => $this->checkForLegacyBackendData($parsedData, $elementType, $elementId)
];
}

public function getElementDataForXliffExport(string $elementType, int $elementId, string $locale): array
Expand Down Expand Up @@ -114,15 +128,23 @@ public function saveElementDataFromXliffImport(string $elementType, int $element
}
}

public function saveElementData(string $elementType, int $elementId, string $integratorName, array $data, bool $merge = false): void
{
$elementMetaData = $this->elementMetaDataRepository->findByIntegrator($elementType, $elementId, $integratorName);
public function saveElementData(
string $elementType,
int $elementId,
string $integratorName,
array $data,
bool $merge = false,
string $releaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC
): void {

$elementMetaData = $this->determinateElementMetaEntity($elementType, $elementId, $integratorName, $releaseType);

if (!$elementMetaData instanceof ElementMetaDataInterface) {
$elementMetaData = new ElementMetaData();
$elementMetaData->setElementType($elementType);
$elementMetaData->setElementId($elementId);
$elementMetaData->setIntegrator($integratorName);
$elementMetaData->setReleaseType($releaseType);
}

$metaDataIntegrator = $this->metaDataIntegratorRegistry->get($integratorName);
Expand All @@ -144,6 +166,42 @@ public function saveElementData(string $elementType, int $elementId, string $int
$this->entityManager->flush();
}

private function determinateElementMetaEntity(
string $elementType,
int $elementId,
string $integratorName,
string $releaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC
): ?ElementMetaDataInterface {

$hasDraft = $this->elementMetaDataExistsWithReleaseType($elementType, $elementId, ElementMetaDataInterface::RELEASE_TYPE_DRAFT);

if ($releaseType === ElementMetaDataInterface::RELEASE_TYPE_PUBLIC && $hasDraft === true) {

// delete draft
$this->deleteElementData($elementType, $elementId, ElementMetaDataInterface::RELEASE_TYPE_DRAFT);

return $this->elementMetaDataRepository->findByIntegrator($elementType, $elementId, $integratorName, $releaseType);
}

return $this->elementMetaDataRepository->findByIntegrator($elementType, $elementId, $integratorName, $releaseType);
}

private function elementMetaDataExistsWithReleaseType(string $elementType, int $elementId, string $releaseType): bool
{
$qb = $this->elementMetaDataRepository->getQueryBuilder();

return $qb
->select('COUNT(e.id)')
->andWhere('e.elementType = :elementType')
->andWhere('e.elementId = :elementId')
->andWhere('e.releaseType = :releaseType')
->setParameter('elementType', $elementType)
->setParameter('elementId', $elementId)
->setParameter('releaseType', $releaseType)
->getQuery()
->getSingleScalarResult() > 0;
}

public function generatePreviewDataForElement(string $elementType, int $elementId, string $integratorName, ?string $template, array $data): array
{
if ($elementType === 'object') {
Expand All @@ -157,9 +215,9 @@ public function generatePreviewDataForElement(string $elementType, int $elementI
return $metaDataIntegrator->getPreviewParameter($element, $template, $data);
}

public function deleteElementData(string $elementType, int $elementId): void
public function deleteElementData(string $elementType, int $elementId, ?string $releaseType = ElementMetaData::RELEASE_TYPE_PUBLIC): void
{
$elementData = $this->elementMetaDataRepository->findAll($elementType, $elementId);
$elementData = $this->elementMetaDataRepository->findAll($elementType, $elementId, $releaseType);

if (count($elementData) === 0) {
return;
Expand All @@ -175,7 +233,7 @@ public function deleteElementData(string $elementType, int $elementId): void
/**
* @return array<int, ElementMetaDataInterface>
*/
protected function checkForLegacyData(array $elements, string $elementType, int $elementId): array
protected function checkForLegacyData(array $elements, string $elementType, int $elementId, string $releaseType = ElementMetaData::RELEASE_TYPE_PUBLIC): array
{
// as soon we have configured seo elements,
// we'll never check the document again. It's all about performance.
Expand All @@ -197,6 +255,7 @@ protected function checkForLegacyData(array $elements, string $elementType, int
$legacyTitleDescription->setElementType($elementType);
$legacyTitleDescription->setElementId($elementId);
$legacyTitleDescription->setIntegrator('title_description');
$legacyTitleDescription->setReleaseType($releaseType);
$legacyTitleDescription->setData(['title' => $legacyData['title'], 'description' => $legacyData['description']]);
$elements[] = $legacyTitleDescription;
}
Expand Down
14 changes: 11 additions & 3 deletions src/Manager/ElementMetaDataManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace SeoBundle\Manager;

use SeoBundle\Model\ElementMetaData;
use SeoBundle\Model\ElementMetaDataInterface;

interface ElementMetaDataManagerInterface
Expand All @@ -13,17 +14,24 @@ public function getMetaDataIntegratorBackendConfiguration(mixed $correspondingEl
/**
* @return array<int, ElementMetaDataInterface>
*/
public function getElementData(string $elementType, int $elementId): array;
public function getElementData(string $elementType, int $elementId, bool $allowDraftReleaseType = false): array;

public function getElementDataForBackend(string $elementType, int $elementId): array;

public function getElementDataForXliffExport(string $elementType, int $elementId, string $locale): array;

public function saveElementDataFromXliffImport(string $elementType, int $elementId, array $rawData, string $locale): void;

public function saveElementData(string $elementType, int $elementId, string $integratorName, array $data, bool $merge = false): void;
public function saveElementData(
string $elementType,
int $elementId,
string $integratorName,
array $data,
bool $merge = false,
string $releaseType = ElementMetaDataInterface::RELEASE_TYPE_PUBLIC
): void;

public function generatePreviewDataForElement(string $elementType, int $elementId, string $integratorName, ?string $template, array $data): array;

public function deleteElementData(string $elementType, int $elementId): void;
public function deleteElementData(string $elementType, int $elementId, ?string $releaseType = ElementMetaData::RELEASE_TYPE_PUBLIC): void;
}
27 changes: 27 additions & 0 deletions src/Migrations/Version20240809095425.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace SeoBundle\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20240809095425 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE seo_element_meta_data ADD release_type VARCHAR(255) DEFAULT "public" NOT NULL;');
$this->addSql('DROP INDEX element_type_id_integrator ON seo_element_meta_data;');
$this->addSql('CREATE UNIQUE INDEX element_type_id_integrator ON seo_element_meta_data (element_type, element_id, integrator, release_type);');
}

public function down(Schema $schema): void
{
}
}
Loading

0 comments on commit 949231f

Please sign in to comment.