Skip to content

[5.x] Element relations not saved when creating an element with Craft::createObject() #16942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

nfourtythree
Copy link
Contributor

@nfourtythree nfourtythree commented Mar 24, 2025

Description

Noticed a quirk/bug when creating an element using Craft::createObject() and setting data on a element relation custom field.

The test code for creating an entry is as follows:

$randomEntry = Entry::find()->orderBy('RAND()')->one();
$section = Craft::$app->getEntries()->getSectionByHandle('test');

$entry = Craft::createObject([
    'class' => Entry::class,
    'sectionId' => $section->id,
    'title' => 'My Test Entry',
    'enabled' => true,
    'myRelatedEntry' => [$randomEntry->id],
]);

Craft::$app->getElements()->saveElement($entry);

With this code the element saves and if you view the element in the CP or look at its content in the DB everything looks correct. The related element shows up in the field etc.

However, no rows are added to the relations DB table. This means that if you were to do an element query e.g. Entry::find()->relatedTo([123])->one() the entry would not be returned.

Tracked this issue down to two parts.

Because the element is being created with createObject() and mass assignment the $_initialized property on the element is still false when it hits the following bit of code, so the field is not marked as dirty.

cms/src/base/Element.php

Lines 5056 to 5058 in f48af60

if ($this->_initialized) {
$this->_dirtyFields[$fieldHandle] = true;
}

This however doesn't stop the content from saving, but in the case of a relationship field it prevents the relation from saving in the updateRelations() method when figuring out if the field should be included.

cms/src/base/Element.php

Lines 6199 to 6205 in f48af60

if (
($this->duplicateOf || $this->isFieldDirty($field->handle) || $field->forceUpdateRelations($this)) &&
(!$this->propagating || $localizeRelations)
) {
$include = true;
break;
}

To get the ball rolling on a solution for this I took the idea that if this element is a brand new element we can pass $isNew from the afterSave() to updateRelations(). As, in theory, if it is new we probably want to be trying to save all the data we can.

Related issues

craftcms/commerce#3931

@nfourtythree nfourtythree self-assigned this Mar 24, 2025
@brandonkelly brandonkelly changed the base branch from 5.x to 4.x March 24, 2025 18:27
@brandonkelly brandonkelly force-pushed the bugfix/element-create-object-not-saving-custom-field-relations branch from dc9f26b to e485b09 Compare March 24, 2025 18:41
[ci skip]
@brandonkelly brandonkelly merged commit cc176a6 into 4.x Mar 24, 2025
@brandonkelly brandonkelly deleted the bugfix/element-create-object-not-saving-custom-field-relations branch March 24, 2025 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants