I'm writing unit tests for a plugin that reacts to adding fields to field layouts, I'm trying to add fields to a layout programmatically but can't get anywhere,
In the example below (method testAddingFieldToEntryType
) after the entry type is saved with amended layout
the layout that comes from $entryType->fieldLayout
and
the layout from \Craft::$app->sections->getEntryTypeById($entryType->id)->fieldLayout)
are different objects, and the latter is empty no matter what I try.
The database looks correct though, I can see the layout, fields and tabs created.
I also tried the solution posted there : Copy the Entry Type along with its field layout with the exact same result.
Any idea what I'm doing wrong ?
Thank you for your time
Steps to reproduce
- Unit test :
class Test extends Unit
{
protected $tester;
public function _fixtures()
{
return [
'sections' => SectionsFixture::class,
'fields' => FieldsFixture::class
];
}
public function testAddingFieldToEntryType()
{
$sectionsFixture = $this->tester->grabFixture('sections');
$fieldsFixture = $this->tester->grabFixture('fields');
$section = $sectionsFixture->getSection(0);
$type = $section->entryTypes[0];
$assetField = $fieldsFixture->getField('assets');
$sectionsFixture->addFieldToEntryType($assetField, $type);
//The following seems correct, and consistent with the database, the layout/tabs ids are not set though :
dump($entryType->fieldLayout);
//This has a correct id (looking at database) and uid, but is empty otherwise :
dd(\Craft::$app->sections->getEntryTypeById($entryType->id)->fieldLayout);
}
}
- Fixtures :
class SectionsFixture extends DbFixture
{
use FileFixtureTrait;
use DbFixtureTrait;
public $dataFile = __DIR__ . '/data/sections.php';
private $_sections = [];
public function load()
{
codecept_debug('Loading sections');
foreach ($this->loadData($this->dataFile) as $key => $data) {
$section = $this->createSection($data);
if (!$this->saveSection($section)) {
throw new \Exception(implode(' ', $section->getErrorSummary(true)));
}
$this->_sections[$key] = $section;
}
}
public function unload()
{
codecept_debug('Unloading sections');
foreach ($this->_sections as $key => $section) {
$this->deleteSection($key);
}
$this->hardDelete();
}
public function deleteSection($key)
{
if (isset($this->_sections[$key])) {
$section = $this->_sections[$key];
unset($this->_sections[$key]);
return \Craft::$app->sections->deleteSection($section);
}
}
public function getSection(string $key): ?Section
{
return $this->_sections[$key] ?? null;
}
public function addFieldToEntryType(Field $field, EntryType $entryType)
{
$layout = $entryType->fieldLayout;
$tab = $layout->tabs[0];
$fields = $layout->fields;
$fields[] = $field;
$layout->fields = $fields;
$tab->elements[] = \Craft::$app->fields->createLayoutElement([
'type' => CustomField::class,
'fieldUid' => $field->uid
]);
if (!\Craft::$app->sections->saveEntryType($entryType)) {
throw new \Exception(implode(' ', $entryType->getErrorSummary(true)));
}
}
protected function createSection(array $data): Section
{
$allSiteSettings = [];
foreach (\Craft::$app->getSites()->getAllSites() as $site) {
$siteSettings = new Section_SiteSettings();
$siteSettings->siteId = $site->id;
$allSiteSettings[$site->id] = $siteSettings;
}
$data['siteSettings'] = $allSiteSettings;
return new Section($data);
}
protected function saveSection(Section $section)
{
return \Craft::$app->sections->saveSection($section);
}
}
class FieldsFixture extends DbFixture
{
use FileFixtureTrait;
use DbFixtureTrait;
public $dataFile = __DIR__ . '/data/fields.php';
private $_fields = [];
public function load()
{
codecept_debug('Loading fields');
foreach ($this->loadData($this->dataFile) as $key => $data) {
$field = $this->createField($data);
if (!$this->saveField($field)) {
throw new \Exception(implode(' ', $field->getErrorSummary(true)));
}
$this->_fields[$key] = $field;
}
}
public function unload()
{
codecept_debug('Unloading fields');
foreach ($this->_fields as $key => $field) {
$this->deleteField($key);
}
$this->hardDelete();
}
public function deleteField($key)
{
if (isset($this->_fields[$key])) {
$field = $this->_fields[$key];
unset($this->_fields[$key]);
return \Craft::$app->fields->deleteField($field);
}
}
public function getField($key): ?Field
{
return $this->_fields[$key] ?? null;
}
protected function createField(array $data): Field
{
$class = $data['type'];
return new $class($data['data']);
}
protected function saveField(Field $field)
{
return \Craft::$app->fields->saveField($field);
}
}
- Data : data/sections.php
return [
[
'handle' => 'myChannel',
'name' => 'My Channel',
'type' => Section::TYPE_CHANNEL
],
[
'handle' => 'myStructure',
'name' => 'My Structure',
'type' => Section::TYPE_STRUCTURE
]
];
data/fields.php
return [
'assets' => [
'type' => Assets::class,
'data' => [
'handle' => 'assets',
'name' => 'Assets'
]
]
];
- Run the test
Additional info
- Craft version: 3.6.18
- PHP version: 7.4
- Database driver & version: mysql 5.7