Skip to content

IBX-11437: Implemented reference aware external storage#730

Open
barw4 wants to merge 4 commits into4.6from
ibx-11437
Open

IBX-11437: Implemented reference aware external storage#730
barw4 wants to merge 4 commits into4.6from
ibx-11437

Conversation

@barw4
Copy link
Contributor

@barw4 barw4 commented Mar 19, 2026

🎫 Issue IBX-11437

Related PRs:

ibexa/admin-ui#1856
https://github.com/ibexa/fieldtype-page/pull/191
https://github.com/ibexa/installer/pull/207

Description:

Problem

When creating a new content version (draft), all field external storage data is fully copied for every translation — even translations not being edited. For field types with complex external storage (e.g. Page Builder with zones, blocks, attributes across multiple tables), this causes thousands of redundant queries per draft creation.

Solution

A new ReferenceAwareExternalStorage interface allows field types to opt out of copying external data for untouched translations during draft creation. Instead of duplicating data, the storage creates a lightweight reference to the source version's data and resolves it transparently on read.

interface ReferenceAwareExternalStorage
{
    public function referenceLegacyField(
        VersionInfo $versionInfo,
        Field $field,
        Field $originalField
    ): ?bool;
}

For QA:

Documentation:

Copy link
Member

@alongosz alongosz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@barw4 nitpick: could you please fix PRs titles so they include a verb per internal conventions? e.g. "Implemented" - ideally in past simple so we don't forget to change it in the merge commit.

More interesting remarks:

Comment on lines +151 to 161
public function createExistingFieldsInNewVersion(Content $content, ?string $editedLanguageCode = null): void
{
foreach ($content->fields as $field) {
if ($field->id === null) {
// Virtual field with default value, skip creating field as it has no id
continue;
}
$this->createExistingFieldInNewVersion($field, $content);

$referenceOnly = $editedLanguageCode !== null && $field->languageCode !== $editedLanguageCode;
$this->createExistingFieldInNewVersion($field, $content, $referenceOnly);
}
Copy link
Member

@alongosz alongosz Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What still worries me is what's gonna happen if a published version had e.g., one translation and the new version draft provides 2 new translations (possible via PHP API). I don't see integration coverage here, so the question is if we cover this anywhere else (ATM of writing this, haven't reviewed the other PRs).

It's especially relevant if all 3 version translations are actually different and should be stored separately.

Copy link
Contributor Author

@barw4 barw4 Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add it this test to https://github.com/ibexa/fieldtype-page/pull/191 (there is integration set there but without this case)

Copy link
Contributor Author

@barw4 barw4 Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused, what do you mean by "draft providing 2 new translations"? According to https://github.com/ibexa/core/blob/4.6/src/contracts/Repository/ContentService.php#L244 we can only pass 1 language when creating a new draft. Maybe you meant publishing version with two languages instead (the test for this case is already there in fieldtype-page)? Am I missing something here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused, what do you mean by "draft providing 2 new translations"? According to https://github.com/ibexa/core/blob/4.6/src/contracts/Repository/ContentService.php#L244 we can only pass 1 language when creating a new draft. Maybe you meant publishing version with two languages instead (the test for this case is already there in fieldtype-page)? Am I missing something here?

Regardless of initialLanguageCode setting, you can pass multiple \Ibexa\Contracts\Core\Repository\Values\Content\Fields with different language codes to \Ibexa\Core\Repository\Values\Content\ContentUpdateStruct::$fields. API should save a draft with all new translations and I'm wondering how this is affecting current changes in PB.


Context:

The $language parameter was added as an attempt to fix validation issues and glue what API expects and offers and what UI has been offering since eZ Publish. So while it can show only one translation, it's quite possible that update operation added or affected more than one translation.

Ref.: ezsystems/ezpublish-kernel#2875

initialLanguageCode itself was added with initial import of "the new" kernel, with its history reaching probably eZ Publish v4 (based on PHPDoc). However the behavior was not consistent with the overall shape of VersionInfo API, hence the attempts to fix it via e.g., the mentioned PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alongosz right, I see, thank you for the explanation.

https://github.com/ibexa/fieldtype-page/pull/191 - I've added the test case in the last commit, I'm not sure the case you mentioned would affect anything though, because external storage is flooded when creating a new draft, not when updating it. Update "lives" its own life, but let me know if this is the case you wanted to see tested.

@barw4 barw4 changed the title IBX-11437: Reference aware external storage IBX-11437: Implemented reference aware external storage Mar 20, 2026
@barw4 barw4 requested a review from alongosz March 20, 2026 13:00
@alongosz
Copy link
Member

Hey @barw4, fixed on 4.6 one of the unrelated PHPStan issues that popped up here, you can rebase :)

@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants