Skip to content

Commit

Permalink
Merge pull request #65 from dachcom-digital/datatype
Browse files Browse the repository at this point in the history
introduce release type
  • Loading branch information
solverat authored Aug 9, 2024
2 parents f8209cd + 17db06c commit 28633a7
Show file tree
Hide file tree
Showing 16 changed files with 240 additions and 41 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The last SEO Bundle for pimcore you'll ever need!

```json
"require" : {
"dachcom-digital/seo" : "~3.0.0",
"dachcom-digital/seo" : "~3.1.0",
}
```

Expand Down
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);
}
}
112 changes: 100 additions & 12 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,22 +128,46 @@ 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);
$sanitizedData = $metaDataIntegrator->validateBeforePersist($elementType, $elementId, $data, $elementMetaData->getData(), $merge);

// remove empty meta data
if ($sanitizedData === null) {

if ($releaseType === ElementMetaDataInterface::RELEASE_TYPE_DRAFT) {

// if draft, we still persist an empty element
// to determinate reset when publish state is incoming

if (
$elementMetaData->getId() > 0 ||
$this->elementMetaDataExistsWithReleaseType($elementType, $elementId, ElementMetaDataInterface::RELEASE_TYPE_PUBLIC, $integratorName)
) {
$this->persistElementMetaData($elementMetaData, []);
}

return;
}

if ($elementMetaData->getId() > 0) {
$this->entityManager->remove($elementMetaData);
$this->entityManager->flush();
Expand All @@ -138,8 +176,12 @@ public function saveElementData(string $elementType, int $elementId, string $int
return;
}

$elementMetaData->setData($sanitizedData);
$this->persistElementMetaData($elementMetaData, $sanitizedData);
}

private function persistElementMetaData(ElementMetaDataInterface $elementMetaData, array $data): void
{
$elementMetaData->setData($data);
$this->entityManager->persist($elementMetaData);
$this->entityManager->flush();
}
Expand All @@ -157,9 +199,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 = ElementMetaDataInterface::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 +217,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 = ElementMetaDataInterface::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 +239,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 Expand Up @@ -264,4 +307,49 @@ protected function getDocumentLegacyData(int $documentId): ?array
'hasTitleDescriptionIntegrator' => $hasTitleDescriptionIntegrator !== false
];
}

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, ?string $integratorName = null): bool
{
$qb = $this->elementMetaDataRepository->getQueryBuilder();

$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);

if ($integratorName !== null) {
$qb
->andWhere('e.integrator = :integratorName')
->setParameter('integratorName', $integratorName);
}

return $qb
->getQuery()
->getSingleScalarResult() > 0;
}

}
Loading

0 comments on commit 28633a7

Please sign in to comment.