final class LayoutBuilderMigration in Panelizer 8.5
Provides functionality to migrate Panelizer data to Layout Builder.
@internal This is an internal part of Panelizer and may be changed or removed at any time without warning. External code should not instantiate this class.
Hierarchy
- class \Drupal\panelizer\LayoutBuilderMigration implements ContainerInjectionInterface
Expanded class hierarchy of LayoutBuilderMigration
3 files declare their use of LayoutBuilderMigration
- LayoutBuilderMigrationConfirmForm.php in src/
Form/ LayoutBuilderMigrationConfirmForm.php - LayoutBuilderMigrationTest.php in tests/
src/ Functional/ LayoutBuilderMigrationTest.php - LayoutBuilderMigrationTest.php in tests/
src/ Kernel/ LayoutBuilderMigrationTest.php
File
- src/
LayoutBuilderMigration.php, line 24
Namespace
Drupal\panelizerView source
final class LayoutBuilderMigration implements ContainerInjectionInterface {
/**
* The Panelizer service.
*
* @var \Drupal\panelizer\PanelizerInterface
*/
private $panelizer;
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private $entityTypeManager;
/**
* The block plugin manager service.
*
* @var \Drupal\Core\Block\BlockManagerInterface
*/
private $blockManager;
/**
* LayoutBuilderMigration constructor.
*
* @param \Drupal\panelizer\PanelizerInterface $panelizer
* The Panelizer service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
* @param \Drupal\Core\Block\BlockManagerInterface $block_manager
* The block plugin manager service.
*/
public function __construct(PanelizerInterface $panelizer, EntityTypeManagerInterface $entity_type_manager, BlockManagerInterface $block_manager) {
$this->panelizer = $panelizer;
$this->entityTypeManager = $entity_type_manager;
$this->blockManager = $block_manager;
module_load_install('panels');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container
->get('panelizer'), $container
->get('entity_type.manager'), $container
->get('plugin.manager.block'));
}
/**
* Migrates a layout-able entity view display to Layout Builder.
*
* @param \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display
* The entity view display.
*/
private function doProcessDisplay(LayoutEntityDisplayInterface $display) {
$entity_type_id = $display
->getTargetEntityTypeId();
$bundle = $display
->getTargetBundle();
$mode = $display
->getMode();
$panelizer_settings = $this->panelizer
->getPanelizerSettings($entity_type_id, $bundle, $mode, $display);
if (empty($panelizer_settings['enable'])) {
return;
}
$display_storage = $this->entityTypeManager
->getStorage('entity_view_display');
$layout_storage = $this->entityTypeManager
->getStorage('layout');
$display
->enableLayoutBuilder()
->setOverridable($panelizer_settings['custom'])
->setThirdPartySetting('layout_library', 'enable', $panelizer_settings['allow']);
$panels_displays = $this->panelizer
->getDefaultPanelsDisplays($entity_type_id, $bundle, $mode, $display);
foreach ($panels_displays as $name => $panels_display) {
$configuration = $panels_display
->getConfiguration();
$configuration += [
'static_context' => [],
];
$section = $this
->toSection($configuration, $entity_type_id, $bundle);
$panels_display
->setConfiguration($configuration);
if ($name === $panelizer_settings['default']) {
$display
->appendSection($section);
if ($configuration['static_context']) {
$display
->setThirdPartySetting('core_context', 'contexts', $configuration['static_context']);
}
}
else {
/** @var \Drupal\layout_library\Entity\Layout $layout */
$layout = $layout_storage
->create([
'id' => implode('_', [
$entity_type_id,
$bundle,
$mode,
$name,
]),
'targetEntityType' => $entity_type_id,
'targetBundle' => $bundle,
'label' => $panels_display
->label(),
]);
$layout
->appendSection($section);
if ($configuration['static_context']) {
$layout
->setThirdPartySetting('core_context', 'contexts', $configuration['static_context']);
}
$layout_storage
->save($layout);
}
}
$display_storage
->save($display);
$panelizer_settings['enable'] = FALSE;
$panelizer_settings['allow'] = FALSE;
$panelizer_settings['custom'] = FALSE;
$this->panelizer
->setPanelizerSettings($entity_type_id, $bundle, $mode, $panelizer_settings, $display);
}
/**
* Migrates a custom entity-specific Panelizer layout to Layout Builder.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity that has the custom layout.
*/
private function doProcessEntity(FieldableEntityInterface $entity) {
$entity_type_id = $entity
->getEntityTypeId();
$bundle = $entity
->bundle();
foreach ($entity->panelizer as $panelizer_item) {
if ($panelizer_item->view_mode === 'full') {
if ($panelizer_item->panels_display) {
$configuration = $panelizer_item->panels_display;
$section = $this
->toSection($configuration, $entity_type_id, $bundle);
/** @var \Drupal\layout_builder\Field\LayoutSectionItemList $sections */
$sections = $entity
->get(OverridesSectionStorage::FIELD_NAME);
$sections
->appendSection($section);
// The Panels display may have been modified by ::toSection() in order
// to make the entity save-able.
$panelizer_item->panels_display = $configuration;
}
if ($panelizer_item->default && $panelizer_item->default !== '__bundle_default__' && $entity
->hasField('layout_selection')) {
$entity->layout_selection->target_id = implode('_', [
$entity_type_id,
$bundle,
$panelizer_item->view_mode,
$panelizer_item->default,
]);
}
$this->entityTypeManager
->getStorage($entity_type_id)
->save($entity);
break;
}
}
}
/**
* Converts a Panels display to a single Layout Builder section.
*
* @param array $configuration
* The Panels display configuration.
* @param string $entity_type_id
* The entity type ID associated with the display.
* @param string $bundle
* The entity bundle associated with the display.
*
* @return \Drupal\layout_builder\Section
* A layout section with the same layout and blocks as the Panels display.
*/
private function toSection(array &$configuration, $entity_type_id, $bundle) {
if (isset($configuration['static_context'])) {
$static_contexts = $configuration['static_context'];
}
else {
$static_contexts = [];
}
$to_component = function (array $block) use ($entity_type_id, $bundle, $static_contexts) {
// Convert ctools_block field blocks to use Layout Builder's field_block.
if ($block['provider'] === 'ctools_block' && strpos($block['id'], 'entity_field:') === 0) {
list(, , $field_name) = explode(':', $block['id']);
$block['provider'] = 'layout_builder';
$block['id'] = "field_block:{$entity_type_id}:{$bundle}:{$field_name}";
// Remove configuration keys that are moved to component-level settings.
unset($block['formatter']['region'], $block['formatter']['weight']);
// If the entity being panelized is referenced in the context mapping,
// use the Layout Builder version of that.
if (isset($block['context_mapping']['entity']) && $block['context_mapping']['entity'] === '@panelizer.entity_context:entity') {
$block['context_mapping']['entity'] = 'layout_builder.entity';
}
}
$plugin_definition = $this->blockManager
->getDefinition($block['id']);
// The required context values must be passed directly in the plugin
// configuration, or the plugin will throw an exception as soon as it is
// instantiated. Note that this is only supported as of Drupal 8.8.
/** @var \Drupal\Component\Plugin\Context\ContextDefinitionInterface $context_definition */
foreach ($plugin_definition['context_definitions'] as $context_name => $context_definition) {
if ($context_definition
->isRequired() && array_key_exists($context_name, $static_contexts)) {
$block['context'][$context_name] = $static_contexts[$context_name]['value'];
}
}
$block['configuration'] = $block;
// Remove keys which are not actually part of the block configuration.
unset($block['configuration']['provider'], $block['configuration']['region'], $block['configuration']['uuid'], $block['configuration']['weight']);
$block += [
'additional' => [],
];
return SectionComponent::fromArray($block);
};
$layout_id = panels_convert_plugin_ids_to_layout_discovery($configuration['layout']);
if ($layout_id) {
$configuration['layout'] = $layout_id;
}
return new Section($configuration['layout'], $configuration['layout_settings'], array_map($to_component, $configuration['blocks']));
}
/**
* Builds a batch definition for a migration to Layout Builder.
*
* @param \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display
* The entity view display to migrate.
*
* @return \Drupal\Core\Batch\BatchBuilder
* The batch definition.
*/
private function buildBatch(LayoutEntityDisplayInterface $display) {
$batch = new BatchBuilder();
// Migrate the Panelizer data in the view display first. Once that's done,
// entity-specific data can be migrated.
$batch
->addOperation([
static::class,
'processDisplay',
], (array) $display
->id());
$entity_type = $this->entityTypeManager
->getDefinition($display
->getTargetEntityTypeId());
$storage = $this->entityTypeManager
->getStorage($entity_type
->id());
$query = $storage
->getQuery()
->exists('panelizer')
->condition('panelizer.view_mode', 'full');
if ($entity_type
->hasKey('bundle')) {
$query
->condition($entity_type
->getKey('bundle'), $display
->getTargetBundle());
}
if ($entity_type
->isRevisionable()) {
$query
->allRevisions();
}
// If the query is looking for revisions, the array keys will be revision
// IDs. In any event, the array keys are always the canonical ID of the
// thing we want to migrate.
foreach (array_keys($query
->execute()) as $entity_id) {
$batch
->addOperation([
static::class,
'processEntity',
], [
$entity_type
->id(),
$entity_id,
]);
}
return $batch;
}
/**
* Creates a migration batch process from an entity view display.
*
* @param \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display
* The entity view display.
*
* @return \Drupal\Core\Batch\BatchBuilder
* The batch definition.
*/
public static function fromDisplay(LayoutEntityDisplayInterface $display) {
return \Drupal::classResolver(static::class)
->buildBatch($display);
}
/**
* Migrates Panelizer data in an entity view display to Layout Builder.
*
* This method is intended to be called as a batch operation.
*
* @param string $id
* The entity view display ID.
*
* @see ::buildBatch()
*/
public static function processDisplay($id) {
$display = EntityViewDisplay::load($id);
assert($display instanceof LayoutEntityDisplayInterface);
\Drupal::classResolver(static::class)
->doProcessDisplay($display);
}
/**
* Migrates custom Panelizer layout data for a single entity.
*
* This method is intended to be called as part of a batch operation.
*
* @param string $entity_type_id
* The entity type ID.
* @param mixed $entity_id
* The ID (or revision ID, if the entity type is revisionable) of the
* entity to load.
*
* @see ::buildBatch()
*/
public static function processEntity($entity_type_id, $entity_id) {
$storage = \Drupal::entityTypeManager()
->getStorage($entity_type_id);
if ($storage
->getEntityType()
->isRevisionable()) {
$entity = $storage
->loadRevision($entity_id);
}
else {
$entity = $storage
->load($entity_id);
}
assert($entity instanceof FieldableEntityInterface);
\Drupal::classResolver(static::class)
->doProcessEntity($entity);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
LayoutBuilderMigration:: |
private | property | The block plugin manager service. | |
LayoutBuilderMigration:: |
private | property | The entity type manager service. | |
LayoutBuilderMigration:: |
private | property | The Panelizer service. | |
LayoutBuilderMigration:: |
private | function | Builds a batch definition for a migration to Layout Builder. | |
LayoutBuilderMigration:: |
public static | function |
Instantiates a new instance of this class. Overrides ContainerInjectionInterface:: |
|
LayoutBuilderMigration:: |
private | function | Migrates a layout-able entity view display to Layout Builder. | |
LayoutBuilderMigration:: |
private | function | Migrates a custom entity-specific Panelizer layout to Layout Builder. | |
LayoutBuilderMigration:: |
public static | function | Creates a migration batch process from an entity view display. | |
LayoutBuilderMigration:: |
public static | function | Migrates Panelizer data in an entity view display to Layout Builder. | |
LayoutBuilderMigration:: |
public static | function | Migrates custom Panelizer layout data for a single entity. | |
LayoutBuilderMigration:: |
private | function | Converts a Panels display to a single Layout Builder section. | |
LayoutBuilderMigration:: |
public | function | LayoutBuilderMigration constructor. |