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

Programmatically Created Entry Save Fails During Title renderObjectTemplate Generation #2705

Closed
sbossarte opened this issue Apr 6, 2018 · 7 comments

Comments

@sbossarte
Copy link
Contributor

sbossarte commented Apr 6, 2018

Description

When programmatically creating a set of fields/entries/etc. Craft 3 will crash. This may be a very specific scenario, or perhaps I'm not using the API as intended any longer. This code did work in a previous RC.

yii\base\UnknownPropertyException: Getting unknown property: craft\elements\Entry::testMatrix in /var/www/vendor/yiisoft/yii2/base/Component.php:154
Stack trace:
#0 /var/www/vendor/craftcms/cms/src/base/Element.php(764): yii\base\Component->__get('testMa...')
#1 /var/www/vendor/yiisoft/yii2/base/ArrayableTrait.php(126): craft\base\Element->__get('testMa...')
#2 /var/www/vendor/craftcms/cms/src/web/View.php(475): yii\base\Model->toArray(Array, Array, false)
#3 /var/www/vendor/craftcms/cms/src/elements/Entry.php(931): craft\web\View->renderObjectTemplate('{section.name|r...', Object(craft\elements\Entry))
#4 /var/www/vendor/craftcms/cms/src/services/Elements.php(353): craft\elements\Entry->beforeSave(false)
#5 /var/www/vendor/xxxxx/xxxxx/src/controllers/xController.php(734): craft\services\Elements->saveElement(Object(craft\elements\Entry))
#6 [internal function]: xxxxx\xxxxx\controllers\xController->actionX()
#7 /var/www/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#8 /var/www/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#9 /var/www/vendor/craftcms/cms/src/web/Controller.php(74): yii\base\Controller->runAction('x', Array)
#10 /var/www/vendor/yiisoft/yii2/base/Module.php(528): craft\web\Controller->runAction('x', Array)
#11 /var/www/vendor/craftcms/cms/src/web/Application.php(238): yii\base\Module->runAction('x/s...', Array)
#12 /var/www/vendor/craftcms/cms/src/web/Application.php(446): craft\web\Application->runAction('x/s...', Array)
#13 /var/www/vendor/craftcms/cms/src/web/Application.php(222): craft\web\Application->_processActionRequest(Object(craft\web\Request))
#14 /var/www/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))
#15 /var/www/html/index.php(21): yii\base\Application->run()
#16 {main}

Steps to reproduce

Create a field group
Create a field for that group
Create a single
Attach field to the single
Modify the entry of that single
Save the entry

// Create a field group.
$fieldgroup = new FieldGroup();
$fieldgroup->name = 'Test Group';
if (!Craft::$app->getFields()->saveGroup($fieldgroup)) {
	return $this->asJson(['error' => Craft::t('test', 'Couldn\'t save field group.')]);
}

// Create matrix.
$matrix = Craft::$app->getFields()->createField([
	'type' => \craft\fields\Matrix::class,
	'groupId' => $fieldgroup->id,
	'name' => 'Test Matrix',
	'handle' => 'testMatrix',
	'instructions' => 'Test instructions.',
	'translationMethod' => Field::TRANSLATION_METHOD_NONE,
	'translationKeyFormat' => null,
	'settings' => [
		'blockTypes' => [],
		'localizeBlocks' => false,
		'minBlocks' => null,
		'maxBlocks' => null,
	]
]);
if (!Craft::$app->getFields()->saveField($matrix)) {
	return $this->asJson(['error' => Craft::t('app', 'Couldn’t save field.')]);
}

// Create single section.
$section = new Section();
$section->name = 'Section Example';
$section->handle = 'sectionExample';
$section->type = 'single';
$section->enableVersioning = false;
$section->propagateEntries = true;
$sitesettings = new Section_SiteSettings();
$sitesettings->siteId = Craft::$app->getSites()->getPrimarySite()->id;
$sitesettings->hasUrls = true;
$sitesettings->uriFormat = 'section-example';
$sitesettings->template = '_section';
$section->setSiteSettings([
	$sitesettings->siteId => $sitesettings
]);
if (!Craft::$app->getSections()->saveSection($section)) {
	return $this->asJson(['error' => Craft::t('app', 'Couldn’t save section.')]);
}

// Attach matrix to entry type via a field layout.
$entrytype = Craft::$app->getSections()->getEntryTypesBySectionId($section->id)[0]; // It's a single, it only has one entry type automatically created for it.
$tab = new FieldLayoutTab();
$tab->name = 'Section Fields';
$tab->sortOrder = 1;
$matrix->required = false;
$matrix->sortOrder = 1;
$tab->setFields([$matrix]);
$fieldlayout = $entrytype->getFieldLayout();
$fieldlayout->setTabs([$tab]);
$fieldlayout->setFields([$matrix]);
$fieldlayout->type = Entry::class;
if (!Craft::$app->getSections()->saveEntryType($entrytype)) {
	return $this->asJson(['error' => Craft::t('test', 'Couldn\'t save entry type.')]);
}

// Add some 'data' to the single's entry.
$entry = Entry::find()->sectionId($section->id)->one();
$entry->setFieldValue('testMatrix', []);

// Save it.
if (!Craft::$app->getElements()->saveElement($entry)) {
	return $this->asJson(['error' => Craft::t('test', 'Couldn\'t save element.')]);
}

Additional info

  • Craft version: 3.0.1
  • PHP version: 7.1.16
  • Database driver & version: MySQL 5.5.56
  • Plugins & versions: None, just the custom module code above.
@Anubarak
Copy link
Contributor

Anubarak commented Apr 8, 2018

Your fieldGroup won't have an ID unless you save it, thus your matrix property groupId is null. When you save it you'll receive an error and the getErrors will contain the message above.

Since you can't save the matrix field you can't attach it to the elements field layout, so it won't have the expected behavior -> the exception is thrown.

In general it is better to include some more if conditions to your code. Your save and create function return bool variables if they were able to store the data or not. When you ignore those it's likely to have unexpected bahaviors. I would say nothing at all in your code is executed because every validation check fails from the very beginning. Save the fieldGroup and your fieldLayout, check the return values and it should be fine

@sbossarte
Copy link
Contributor Author

You are correct, I was trying to strip down my example code, which was setting up a lot more than just the given entry, and must have removed those save statements as well. I have updated the comment with the correct code.

@Anubarak
Copy link
Contributor

Anubarak commented Apr 8, 2018

Seems like you still don't save the field layout

@sbossarte
Copy link
Contributor Author

Saving an entry type also saves the associated field layout:

Craft::$app->getFields()->saveLayout($fieldLayout);

@brandonkelly
Copy link
Member

@sbossarte looking through the stack trace, what is the last step in there that refers to the above code? Which line in the code is it referring to?

@sbossarte
Copy link
Contributor Author

sbossarte commented Apr 9, 2018

@brandonkelly This would be the line in the stack trace:

#5 /var/www/vendor/xxxxx/xxxxx/src/controllers/xController.php(734): craft\services\Elements->saveElement(Object(craft\elements\Entry))

And its associated example line where it breaks.

// Save it.
if (!Craft::$app->getElements()->saveElement($entry)) {

@brandonkelly
Copy link
Member

Thanks! Fixed for the next release.

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

No branches or pull requests

3 participants