Skip to content

Instantly share code, notes, and snippets.

@artyuum
Last active February 8, 2021 06:19
Show Gist options
  • Save artyuum/0bb26a93798ff99dfcbe1211e14dd916 to your computer and use it in GitHub Desktop.
Save artyuum/0bb26a93798ff99dfcbe1211e14dd916 to your computer and use it in GitHub Desktop.
A simple helper to ease with the creation of custom fields on Drupal without having to use YAML files as they are less convenient.
<?php
namespace Drupal\artyuum\Helper;
use Drupal;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* This helper is used to ease with the creation of custom fields in PHP without having to use YAML files as they are less convenient.
*/
class FieldCreationHelper
{
/**
* @var string Should contain the entity type (e.g "node", "user", etc).
*/
private $entityType;
/**
* @var string Should contain the field machine name (e.g. "my_field_name").
*/
private $fieldName;
/**
* @var string Should contain the field type (e.g. "string", "integer", etc.).
*/
private $fieldType;
/**
* @var string Should contain the field label (e.g. "Something").
*/
private $fieldLabel;
/**
* @var string Should contain the field form type (e.g. "text_textfield", "number", etc.).
*/
private $fieldFormType;
/**
* @var array Should contain the node type that will have this field (e.g ['page', 'article']).
*/
private $bundles;
/**
* @var int Should contain the field's weight (NOTE: seems like this is not working)
*/
private $weight = 20;
/**
* @var string Should contain the region form (e.g. "content", "hidden", etc.)
*/
private $regionForm = 'content';
/**
* @var int Should contain the limit of selected option. (-1 for unlimuted)
*/
private $cardinality = 1;
/**
* @var array Should contain the storage settings which is usually used to set the allowed values for a field or the target type (when making a relation to an entity)
*/
private $storageSettings = [];
/**
* @var array Should contain the field settings which is usually used to set the entity machine name (when making a relation to an entity)
*/
private $fieldSettings = [];
/**
* @var bool should contain whether this field is required or not
*/
private $required = true;
public function __construct(string $entityType, string $fieldName, string $fieldType, string $fieldLabel, string $fieldFormType, array $bundles)
{
$this->entityType = $entityType;
$this->fieldName = $fieldName;
$this->fieldType = $fieldType;
$this->fieldLabel = $fieldLabel;
$this->fieldFormType = $fieldFormType;
$this->bundles = $bundles;
}
public function getEntityType(): string
{
return $this->entityType;
}
public function setEntityType(string $entityType): self
{
$this->entityType = $entityType;
return $this;
}
public function getFieldName(): string
{
if ($this->fieldName === 'body') {
return $this->fieldName;
}
return 'field_' . $this->fieldName;
}
public function setFieldName(string $fieldName): self
{
$this->fieldName = $fieldName;
return $this;
}
public function getFieldType(): string
{
return $this->fieldType;
}
public function setFieldType(string $fieldType): self
{
$this->fieldType = $fieldType;
return $this;
}
public function getFieldLabel(): string
{
return $this->fieldLabel;
}
public function setFieldLabel(string $fieldLabel): self
{
$this->fieldLabel = $fieldLabel;
return $this;
}
public function getFieldFormType(): string
{
return $this->fieldFormType;
}
public function setFieldFormType(string $fieldFormType): self
{
$this->fieldFormType = $fieldFormType;
return $this;
}
public function getBundles(): array
{
return $this->bundles;
}
public function setBundles(array $bundles): self
{
$this->bundles = $bundles;
return $this;
}
public function getWeight(): int
{
return $this->weight;
}
public function setWeight(int $weight): self
{
$this->weight = $weight;
return $this;
}
public function getRegionForm(): string
{
return $this->regionForm;
}
public function setRegionForm(string $regionForm): self
{
$this->regionForm = $regionForm;
return $this;
}
public function getCardinality(): int
{
return $this->cardinality;
}
public function setCardinality(int $cardinality): self
{
$this->cardinality = $cardinality;
return $this;
}
public function getStorageSettings(): array
{
return $this->storageSettings;
}
public function setStorageSettings(array $storageSettings): self
{
$this->storageSettings = $storageSettings;
return $this;
}
public function getFieldSettings(): array
{
return $this->fieldSettings;
}
public function setFieldSettings(array $fieldSettings): self
{
$this->fieldSettings = $fieldSettings;
return $this;
}
public function getRequired(): bool
{
return $this->required;
}
public function setRequired(bool $required): self
{
$this->required = $required;
return $this;
}
/**
* Creates a new field.
*
* @throws EntityStorageException
*/
public function create(): void
{
$fieldStorage = FieldStorageConfig::loadByName($this->getEntityType(), $this->getFieldName());
// creates the field only if it doesn't already exist
if (!$fieldStorage) {
FieldStorageConfig::create([
'field_name' => $this->getFieldName(),
'entity_type' => $this->getEntityType(),
'type' => $this->getFieldType(),
'weight' => $this->getWeight(),
'cardinality' => $this->getCardinality(),
'settings' => $this->getStorageSettings(),
])->save();
$fieldStorage = FieldStorageConfig::loadByName($this->getEntityType(), $this->getFieldName());
}
// loops through all bundles and assigns the field
foreach ($this->getBundles() as $bundle) {
$field = FieldConfig::loadByName($this->getEntityType(), $bundle, $this->getFieldName());
if (!$field) {
FieldConfig::create([
'field_storage' => $fieldStorage,
'bundle' => $bundle,
'label' => $this->getFieldLabel(),
'settings' => $this->getFieldSettings(),
'required' => $this->getRequired(),
])->save();
/** @var Drupal\Core\Entity\EntityDisplayRepository $displayRepository */
$displayRepository = Drupal::service('entity_display.repository');
$displayRepository->getFormDisplay($this->getEntityType(), $bundle)
->setComponent($this->getFieldName(), [
'region' => $this->getRegionForm(),
'type' => $this->getFieldFormType(),
])->save();
$displayRepository->getViewDisplay($this->getEntityType(), $bundle)
->setComponent($this->getFieldName(), [
'label' => 'hidden',
'type' => 'text_default',
])->save();
}
}
}
}
@artyuum
Copy link
Author

artyuum commented Feb 8, 2021

Usage

(new FieldCreationHelper('node', 'youtube_video_ids', 'string', 'YouTube video IDs', 'string_textfield', ['article']))
    ->setCardinality(-1) // unlimited values
    ->create()
;

All field's name will be prefixed with "field_" (unless the field name is "body"). So for the code above, the field will be created as "field_youtube_video_ids".

Fields are created as required by default. You can change that by calling the following setRequired() method before calling create(), like this:

(new FieldCreationHelper('node', 'youtube_video_ids', 'string', 'YouTube video IDs', 'string_textfield', ['article']))
    ->setCardinality(-1) // unlimited values
    ->setRequired(false) // not required
    ->create()
;

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