Skip to content
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

[4.x]: Entry title formats containing element queries with custom select statement breaks in unexpected ways #13392

Closed
MoritzLost opened this issue Jul 6, 2023 · 9 comments

Comments

@MoritzLost
Copy link
Contributor

MoritzLost commented Jul 6, 2023

What happened?

Description

I just fixed a very curious issue with the Title Format setting for entry types. I had a title format defined like this (course_category is a categories field):

{course_category.select('title').column()|join(' / ')}

This worked, but was causing curious validation errors when the entry was saved:

Invalid Configuration – yii\base\InvalidConfigException
Category is missing its group ID

Switching to an unoptimized query fixes this:

{course_category.all()|column('title')|join(' / ')}

Not quite sure what's going on here – I'm guessing because of the overwritten query, the Entry object will contain Category objects that are missing some properties? Or something involving the query cache?

Maybe this can be fixed by rendering the template format with a copy of the Entry object? Or execute it in a way that won't cause any queries executed inside it to 'leak' or be cached?

If this can't be fixed, this should probably be mentioned in the docs.

Craft CMS version

4.4.15

PHP version

8.2

Operating system and version

No response

Database type and version

No response

Image driver and version

No response

Installed plugins and versions

No response

@brandonkelly
Copy link
Member

Search for that Category is missing its group ID message in storage/logs/. If it’s in there, can you post the stack trace that follows it?

@MoritzLost
Copy link
Contributor Author

@brandonkelly Sure:

2023-07-06 14:56:44 [web.ERROR] [yii\base\InvalidConfigException] yii\base\InvalidConfigException: Category is missing its group ID in /path/to/project/vendor/craftcms/cms/src/elements/Category.php:736
Stack trace:
#0 /path/to/project/vendor/craftcms/cms/src/elements/Category.php(404): craft\elements\Category->getGroup()
#1 /path/to/project/vendor/craftcms/cms/src/helpers/ElementHelper.php(128): craft\elements\Category->getUriFormat()
#2 /path/to/project/vendor/craftcms/cms/src/validators/ElementUriValidator.php(56): craft\helpers\ElementHelper::setUniqueUri(Object(craft\elements\Category))
#3 /path/to/project/vendor/yiisoft/yii2/validators/Validator.php(260): craft\validators\ElementUriValidator->validateAttribute(Object(craft\elements\Category), 'uri')
#4 /path/to/project/vendor/yiisoft/yii2/base/Model.php(368): yii\validators\Validator->validateAttributes(Object(craft\elements\Category), Array)
#5 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2374): yii\base\Model->validate(Array, true)
#6 /path/to/project/vendor/craftcms/cms/src/fields/BaseRelationField.php(530): craft\base\Element->validate()
#7 /path/to/project/vendor/craftcms/cms/src/fields/BaseRelationField.php(481): craft\fields\BaseRelationField::_validateRelatedElement(Object(craft\elements\Category))
#8 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2512): craft\fields\BaseRelationField->validateRelatedElements(Object(craft\elements\Entry), NULL)
#9 /path/to/project/vendor/yiisoft/yii2/validators/InlineValidator.php(77): craft\base\Element->validateCustomFieldAttribute('field:course_ca...', Array, Object(yii\validators\InlineValidator), Object(craft\elements\db\CategoryQuery))
#10 /path/to/project/vendor/yiisoft/yii2/validators/Validator.php(260): yii\validators\InlineValidator->validateAttribute(Object(craft\elements\Entry), 'field:course_ca...')
#11 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2413): yii\validators\Validator->validateAttributes(Object(craft\elements\Entry))
#12 /path/to/project/vendor/yiisoft/yii2/base/Model.php(370): craft\base\Element->afterValidate()
#13 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2374): yii\base\Model->validate(Array, true)
#14 /path/to/project/vendor/craftcms/cms/src/services/Elements.php(2969): craft\base\Element->validate()
#15 /path/to/project/vendor/craftcms/cms/src/services/Elements.php(1062): craft\services\Elements->_saveElementInternal(Object(craft\elements\Entry), true, false, NULL, Array, false)
#16 /path/to/project/vendor/craftcms/cms/src/controllers/ElementsController.php(957): craft\services\Elements->saveElement(Object(craft\elements\Entry))
#17 [internal function]: craft\controllers\ElementsController->actionSave()
#18 /path/to/project/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#19 /path/to/project/vendor/yiisoft/yii2/base/Controller.php(178): yii\base\InlineAction->runWithParams(Array)
#20 /path/to/project/vendor/yiisoft/yii2/base/Module.php(552): yii\base\Controller->runAction('save', Array)
#21 /path/to/project/vendor/craftcms/cms/src/web/Application.php(302): yii\base\Module->runAction('elements/save', Array)
#22 /path/to/project/vendor/craftcms/cms/src/web/Application.php(627): craft\web\Application->runAction('elements/save', Array)
#23 /path/to/project/vendor/craftcms/cms/src/web/Application.php(281): craft\web\Application->_processActionRequest(Object(craft\web\Request))
#24 /path/to/project/vendor/yiisoft/yii2/base/Application.php(384): craft\web\Application->handleRequest(Object(craft\web\Request))
#25 /path/to/project/web/index.php(11): yii\base\Application->run()
#26 /Users/moritz/.composer/vendor/laravel/valet/server.php(110): require('/Users/moritz/D...')
#27 {main} {"memory":9459760,"exception":"[object] (yii\\base\\InvalidConfigException(code: 0): Category is missing its group ID at /path/to/project/vendor/craftcms/cms/src/elements/Category.php:736)"} 

@brandonkelly
Copy link
Member

Are you sure you’re on 4.4.15? Have you made any changes to vendor/craftcms/cms/src/base/Element.php? Because the line numbers in the stack trace don’t make any sense.

For example, this line:

#11 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2413): yii\validators\Validator->validateAttributes(Object(craft\elements\Entry))

refers to this line in Element.php in 4.4.15:

@MoritzLost
Copy link
Contributor Author

MoritzLost commented Jul 7, 2023

@brandonkelly Sorry, I tested this before and after the update to 4.4.15, I think I might've copied a stack trace from the earlier version. My bad!

I'm still getting the error on 4.4.15, here's the correct stack trace:

2023-07-07 13:57:08 [web.ERROR] [yii\base\InvalidConfigException] yii\base\InvalidConfigException: Category is missing its group ID in /path/to/project/vendor/craftcms/cms/src/elements/Category.php:738
Stack trace:
#0 /path/to/project/vendor/craftcms/cms/src/elements/Category.php(404): craft\elements\Category->getGroup()
#1 /path/to/project/vendor/craftcms/cms/src/helpers/ElementHelper.php(128): craft\elements\Category->getUriFormat()
#2 /path/to/project/vendor/craftcms/cms/src/validators/ElementUriValidator.php(56): craft\helpers\ElementHelper::setUniqueUri(Object(craft\elements\Category))
#3 /path/to/project/vendor/yiisoft/yii2/validators/Validator.php(260): craft\validators\ElementUriValidator->validateAttribute(Object(craft\elements\Category), 'uri')
#4 /path/to/project/vendor/yiisoft/yii2/base/Model.php(368): yii\validators\Validator->validateAttributes(Object(craft\elements\Category), Array)
#5 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2419): yii\base\Model->validate(Array, true)
#6 /path/to/project/vendor/craftcms/cms/src/fields/BaseRelationField.php(530): craft\base\Element->validate()
#7 /path/to/project/vendor/craftcms/cms/src/fields/BaseRelationField.php(481): craft\fields\BaseRelationField::_validateRelatedElement(Object(craft\elements\Category))
#8 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2557): craft\fields\BaseRelationField->validateRelatedElements(Object(craft\elements\Entry), NULL)
#9 /path/to/project/vendor/yiisoft/yii2/validators/InlineValidator.php(77): craft\base\Element->validateCustomFieldAttribute('field:course_ca...', Array, Object(yii\validators\InlineValidator), Object(craft\elements\db\CategoryQuery))
#10 /path/to/project/vendor/yiisoft/yii2/validators/Validator.php(260): yii\validators\InlineValidator->validateAttribute(Object(craft\elements\Entry), 'field:course_ca...')
#11 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2458): yii\validators\Validator->validateAttributes(Object(craft\elements\Entry))
#12 /path/to/project/vendor/yiisoft/yii2/base/Model.php(370): craft\base\Element->afterValidate()
#13 /path/to/project/vendor/craftcms/cms/src/base/Element.php(2419): yii\base\Model->validate(Array, true)
#14 /path/to/project/vendor/craftcms/cms/src/services/Elements.php(3008): craft\base\Element->validate()
#15 /path/to/project/vendor/craftcms/cms/src/services/Elements.php(1062): craft\services\Elements->_saveElementInternal(Object(craft\elements\Entry), true, false, NULL, Array, false)
#16 /path/to/project/vendor/craftcms/cms/src/controllers/ElementsController.php(942): craft\services\Elements->saveElement(Object(craft\elements\Entry))
#17 [internal function]: craft\controllers\ElementsController->actionSave()
#18 /path/to/project/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#19 /path/to/project/vendor/yiisoft/yii2/base/Controller.php(178): yii\base\InlineAction->runWithParams(Array)
#20 /path/to/project/vendor/yiisoft/yii2/base/Module.php(552): yii\base\Controller->runAction('save', Array)
#21 /path/to/project/vendor/craftcms/cms/src/web/Application.php(304): yii\base\Module->runAction('elements/save', Array)
#22 /path/to/project/vendor/craftcms/cms/src/web/Application.php(607): craft\web\Application->runAction('elements/save', Array)
#23 /path/to/project/vendor/craftcms/cms/src/web/Application.php(283): craft\web\Application->_processActionRequest(Object(craft\web\Request))
#24 /path/to/project/vendor/yiisoft/yii2/base/Application.php(384): craft\web\Application->handleRequest(Object(craft\web\Request))
#25 /path/to/project/web/index.php(11): yii\base\Application->run()
#26 /Users/moritz/.composer/vendor/laravel/valet/server.php(110): require('/Users/moritz/D...')
#27 {main} {"memory":5188696,"exception":"[object] (yii\\base\\InvalidConfigException(code: 0): Category is missing its group ID at /path/to/project/vendor/craftcms/cms/src/elements/Category.php:738)"} 

@brandonkelly
Copy link
Member

Thanks! I see what’s going on now.

The issue is that the overridden select value is sticking around on the query, which is affecting the Categories field when it fetches the field value to validate the related categories.

This sort of thing is usually not an issue anymore in Craft 4 due to #8781, but still applies in this case because the Title Format object template doesn’t pull field values in via the magic getter.

You can solve it by cloning the category query via clone() from your Title Format template, before modifying it:

{clone(course_category).select('title').column()|join(' / ')}

@MoritzLost
Copy link
Contributor Author

@brandonkelly Thanks for the explanation! Yeah, cloning is one option, as is the unoptimized query (the overhead doesn't really matter in that context). But shouldn't this be fixed in core, or at least mentioned in the docs? This error is going to be insanely hard to find the cause of if someone encounters it …

brandonkelly added a commit that referenced this issue Jul 17, 2023
@brandonkelly
Copy link
Member

We discussed this today and decided to update Element::toArray() so object templates like Title Format get the same auto-cloning treatment as Element::_get(). So this will be fixed in the next release.

@brandonkelly
Copy link
Member

Craft 4.4.16 is out with that fix.

@MoritzLost
Copy link
Contributor Author

@brandonkelly Sounds great, thanks!

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

No branches or pull requests

2 participants