kaliop-uk / ezmigrationbundle

This bundle makes it easy to handle eZPlatform / eZPublish5 content upgrades/migrations
GNU General Public License v2.0
53 stars 81 forks source link

Cannot completely remove object relation attribute #228

Open SalvatorePollaci opened 4 years ago

SalvatorePollaci commented 4 years ago

I have run the following migration to remove the 'product_categories' object relation list attribute(list of 'product_category' content type objects) from my 'recipe' content type:

-
    type: content_type
    mode: update
    content_type_group: Content
    identifier: recipe
    remove_attributes: [product_categories]

Now if I view the 'recipe' content type definition from eZ's backoffice I no longer see the 'product_categories' object relation list attribute, BUT, from a recipe content objects 'Relations' tab I still see the relation with the previously associated product category.

recipe_product_category_related_objects

So now If I try to update such recipe content via eZ's ContentService(eZ\Publish\Core\Repository\ContentService) updateContent method I get the following notice 'Notice: Trying to get property of non-object' from vendor/ezsystems/ezpublish-kernel/eZ/Publish/Core/Repository/RelationProcessor.php processFieldRelations method.

public function processFieldRelations(
        array $inputRelations,
        $sourceContentId,
        $sourceContentVersionNo,
        ContentType $contentType,
        array $existingRelations = array()
    ) {
        // Map existing relations for easier handling
        $mappedRelations = array();
        foreach ($existingRelations as $relation) {
            if ($relation->type === Relation::FIELD) {
                $fieldDefinitionId = $contentType->getFieldDefinition($relation->sourceFieldDefinitionIdentifier)->id;
                $mappedRelations[$relation->type][$fieldDefinitionId][$relation->destinationContentInfo->id] = $relation;
            }
            // Using bitwise AND as Legacy Stack stores COMMON, LINK and EMBED relation types
            // in the same entry using bitmask
            if ($relation->type & Relation::LINK) {
                $mappedRelations[Relation::LINK][$relation->destinationContentInfo->id] = $relation;
            }
            if ($relation->type & Relation::EMBED) {
                $mappedRelations[Relation::EMBED][$relation->destinationContentInfo->id] = $relation;
            }
        }

Simply put, the previous version of the 'recipe' content still contains the 'product_categories' relation, but now the relation's 'sourceFieldDefinitionIdentifier'

$relation->sourceFieldDefinitionIdentifier

is null, resulting in the highlighted notice. On the other hand, if I re-publish the recipe content from eZ's backoffice, all goes well, and the relation is no longer visible from the 'Relations' tab.

Is this a bug in eZ Migration Bundle? If so, how can I programmatically re-publish the recipe contents without such notices?

SalvatorePollaci commented 4 years ago

After a lot of debugging I found out that the sticky information was coming from the 'ezcontentobject_link' table. So after running the following query:

DELETE FROM ezcontentobject_link
WHERE contentclassattribute_id = XXX

the relation was no longer visible in the 'Relations tab', moreover I was able to programmatically re-publish the recipe contents without any notices.

Maybe such query should be automatically run my eZ Migration bundle when removing object relation list attributes?

gggeek commented 4 years ago

I think that what you are experiencing might be a bug in the eZ kernel, and should be reported in the upstream bug tracker.

Of course it is entirely possible for you to add a 'sql' step to your yml migration definition that does the clean up of the ezcontentobject_link table after removing the object-relation field (I can provide an example of that if needed).

However, I am not sure that it is the duty of the migration bundle to execute that automatically:

a) is it really the correct thing to do? As far as I understand, the problem comes from current (as well as old) versions of objects having more data than they should have if matching the current ContentType definition. This seems to be a generic problem, that might happen for every field type which stores data in a custom table besides ezcontentobject_attribute or external system. Does the kernel already drop that custom data? If not, why? Are there performance implications (think about 10M objects)? Also, the reverse case can also happen: does the kernel allow one to add a new non-null field to a ContentType with existing contents? If so, existing contents will also be inconsistent with their current definition. Should the kernel disallow that, or maybe better allow to do that but set a default non-null value for all objects and their previous versions? Last but not least: what happens when an editor tries to preview/restore an old content version which did not have the new field?

b) assuming that it is the correct thing to do, it seems something that the kernel should do automatically

gggeek commented 3 years ago

Ping @SalvatorePollaci any news about this? If you agree this is a kernel bug, I'd like to close this ticket...