diff --git a/config/schema/paragraphs_type.schema.yml b/config/schema/paragraphs_type.schema.yml index fe853eb..984f301 100644 --- a/config/schema/paragraphs_type.schema.yml +++ b/config/schema/paragraphs_type.schema.yml @@ -8,6 +8,19 @@ paragraphs.paragraphs_type.*: label: type: label label: 'Label' + feature_plugins: + type: sequence + label: 'Plugins' + sequence: + type: mapping + label: 'Layout plugins configuration' + mapping: + enabled: + type: boolean + label: 'Enabled' + weight: + type: integer + label: 'Weight' entity_reference_selection.default:paragraph: type: entity_reference_selection diff --git a/paragraphs.api.php b/paragraphs.api.php new file mode 100644 index 0000000..8e01ef3 --- /dev/null +++ b/paragraphs.api.php @@ -0,0 +1,28 @@ +getRevisionAuthor()) { $this->setRevisionAuthorId($this->getOwnerId()); } + + if ($this->unserializedFeatureSettings) { + $this->set('feature_settings', serialize($this->unserializedFeatureSettings)); + } + else { + $this->set('feature_settings', serialize([])); + } + } + + /** + * Sets the un-serialized feature settings. + * + * @param $feature_settings + * The feature settings from the form. + */ + public function setUnserializedSettings($feature_settings) { + // Set feature settings field. + $this->unserializedFeatureSettings = $feature_settings; } /** @@ -175,8 +199,20 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface, EntityN /** * {@inheritdoc} */ - public function getData() { - return $this->get('data')->value; + public function getFeatureSettings($key = array(), $index = NULL) { + if ($this->get('feature_settings')->value) { + $this->unserializedData = unserialize($this->get('feature_settings')->value); + } + else { + $this->unserializedData = []; + } + if (empty($key)) { + return $this->unserializedData; + } + if ($index) { + $key = array_merge($key, array($index)); + } + return NestedArray::getValue($this->unserializedData, $key); } /** @@ -296,6 +332,10 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface, EntityN ->setSetting('is_ascii', TRUE) ->setSetting('max_length', FieldStorageConfig::NAME_MAX_LENGTH); + $fields['feature_settings'] = BaseFieldDefinition::create('string_long') + ->setLabel(t('Feature settings')) + ->setDescription(t('The feature plugin settings')); + return $fields; } diff --git a/src/Entity/ParagraphsType.php b/src/Entity/ParagraphsType.php index b57b337..7b20631 100644 --- a/src/Entity/ParagraphsType.php +++ b/src/Entity/ParagraphsType.php @@ -28,6 +28,7 @@ use Drupal\paragraphs\ParagraphsTypeInterface; * config_export = { * "id", * "label", + * "feature_plugins", * }, * bundle_of = "paragraph", * links = { @@ -54,4 +55,11 @@ class ParagraphsType extends ConfigEntityBundleBase implements ParagraphsTypeInt */ public $label; + /** + * The ParagraphsType plugins. + * + * @var array + */ + public $feature_plugins = []; + } diff --git a/src/Form/ParagraphsTypeForm.php b/src/Form/ParagraphsTypeForm.php index ad63cd9..41359ac 100644 --- a/src/Form/ParagraphsTypeForm.php +++ b/src/Form/ParagraphsTypeForm.php @@ -2,9 +2,12 @@ namespace Drupal\paragraphs\Form; +use Drupal\Component\Utility\Xss; use Drupal\Core\Entity\EntityForm; use Drupal\Core\Form\FormStateInterface; use Drupal\field_ui\FieldUI; +use Drupal\paragraphs\ParagraphsTypeFeatureManager; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Form controller for paragraph type forms. @@ -12,6 +15,32 @@ use Drupal\field_ui\FieldUI; class ParagraphsTypeForm extends EntityForm { /** + * The paragraphs type feature plugin manager service. + * + * @var \Drupal\paragraphs\ParagraphsTypeFeatureManager + */ + protected $paragraphsTypeFeatureManager; + + /** + * GeneralSettingsForm constructor. + * + * @param \Drupal\paragraphs\ParagraphsTypeFeatureManager $paragraphs_type_feature_manager + * The paragraphs type feature manager service. + */ + public function __construct(ParagraphsTypeFeatureManager $paragraphs_type_feature_manager) { + $this->paragraphsTypeFeatureManager = $paragraphs_type_feature_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.paragraphs_type.feature') + ); + } + + /** * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { @@ -41,7 +70,41 @@ class ParagraphsTypeForm extends EntityForm { '#disabled' => !$paragraphs_type->isNew(), ); - // You will need additional form elements for your custom properties. + $config = $paragraphs_type->get('feature_plugins'); + $feature_plugins = $this->paragraphsTypeFeatureManager->getDefinitions(); + $weight = count($feature_plugins) + 1; + $feature_plugins_order = []; + foreach ($feature_plugins as $id => $feature_plugin) { + $feature_plugins_order[$id] = [ + 'label' => $feature_plugin['label'], + 'enabled' => isset($config[$id]['enabled']) ? $config[$id]['enabled'] : FALSE, + 'weight' => isset($config[$id]['weight']) ? $config[$id]['weight'] : $weight, + ]; + $weight++; + } + + $form['feature_plugins'] = [ + '#type' => 'table', + '#header' => [t('Feature'), t('Description')], + '#empty' => t('There are no plugins yet. Add a plugin.'), + '#suffix' => '
' . $this->t('The feature plugins that are enabled to manage Paragraphs display.') .'
', + ]; + + uasort($feature_plugins_order, 'Drupal\Component\Utility\SortArray::sortByWeightElement'); + + foreach ($feature_plugins_order as $id => $feature_plugin) { + $description = $this->paragraphsTypeFeatureManager->getDefinition($id)['description']; + $form['feature_plugins'][$id]['enabled'] = [ + '#type' => 'checkbox', + '#title' => $feature_plugin['label'], + '#title_display' => 'after', + '#default_value' => $feature_plugin['enabled'], + ]; + $form['feature_plugins'][$id]['description'] = [ + '#type' => 'markup', + '#markup' => isset($description) ? Xss::filter($description) : '', + ]; + } return $form; } diff --git a/src/ParagraphsTypeFeatureBase.php b/src/ParagraphsTypeFeatureBase.php new file mode 100644 index 0000000..6e13474 --- /dev/null +++ b/src/ParagraphsTypeFeatureBase.php @@ -0,0 +1,110 @@ +configFactory = $config; + $this->entityTypeManager = $entity_type_manager; + $this->configuration += $this->defaultConfiguration(); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('config.factory'), + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + } + + /** + * {@inheritdoc} + */ + public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return []; + } + + /** + * {@inheritdoc} + */ + public function getConfiguration() { + return []; + } + + /** + * {@inheritdoc} + */ + public function setConfiguration(array $configuration) { + } + + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + return []; + } + +} diff --git a/src/ParagraphsTypeFeatureInterface.php b/src/ParagraphsTypeFeatureInterface.php new file mode 100644 index 0000000..8143b37 --- /dev/null +++ b/src/ParagraphsTypeFeatureInterface.php @@ -0,0 +1,24 @@ +setCacheBackend($cache_backend, 'paragraphs_type_feature_builder_plugins'); + $this->alterInfo('paragraphs_type_feature_builder_info'); + $this->entityTypeManager = $entity_type_manager; + // @todo define settings for the plugins. + $this->config = $config_factory->get('paragraphs.paragraphs_type'); + } + +} diff --git a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php index 01a5f8d..7818b7c 100644 --- a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php +++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php @@ -592,6 +592,18 @@ class InlineParagraphsWidget extends WidgetBase { $element['subform'] = array(); } + $paragraphs_type = paragraphs\Entity\ParagraphsType::load($paragraphs_entity->getType()); + if ($paragraphs_type) { + $config = \Drupal::config('paragraphs.paragraphs_type.' . $paragraphs_type->id()); + foreach ($config->get('feature_plugins') as $plugin_id => $plugin) { + if ($plugin['enabled'] == TRUE) { + $plugin_instance = \Drupal::service('plugin.manager.paragraphs_type.feature')->createInstance($plugin_id); + $element['feature'][$plugin_id] = []; + $display->buildForm($paragraphs_entity, $element['feature'][$plugin_id], $form_state); + $element['feature'][$plugin_id] = $plugin_instance->buildFeaturesForm($paragraphs_entity); + } + } + } $element['subform']['#attributes']['class'][] = 'paragraphs-subform'; $element['subform']['#access'] = $paragraphs_entity->access('update'); @@ -1059,6 +1071,9 @@ class InlineParagraphsWidget extends WidgetBase { if ($widget_state['paragraphs'][$delta]['mode'] == 'edit') { // Extract the form values on submit for getting the current paragraph. $display->extractFormValues($entity, $element['subform'], $form_state); + if (isset($item['feature'])) { + $display->extractFormValues($entity, $element['feature'], $form_state); + } $display->validateFormValues($entity, $element['subform'], $form_state); } } @@ -1095,7 +1110,6 @@ class InlineParagraphsWidget extends WidgetBase { && $widget_state['paragraphs'][$item['_original_delta']]['mode'] != 'remove') { $paragraphs_entity = $widget_state['paragraphs'][$item['_original_delta']]['entity']; - /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $display */ $display = $widget_state['paragraphs'][$item['_original_delta']]['display']; if ($widget_state['paragraphs'][$delta]['mode'] == 'edit') { @@ -1115,6 +1129,10 @@ class InlineParagraphsWidget extends WidgetBase { $paragraphs_entity->set($langcode_key, $form_state->get('langcode')); } } + if (isset($item['feature'])) { + $paragraphs_entity->setUnserializedSettings($item['feature']); + } + $paragraphs_entity->setNeedsSave(TRUE); $item['entity'] = $paragraphs_entity; $item['target_id'] = $paragraphs_entity->id(); diff --git a/src/Tests/ParagraphsPluginsTest.php b/src/Tests/ParagraphsPluginsTest.php new file mode 100644 index 0000000..779fdbc --- /dev/null +++ b/src/Tests/ParagraphsPluginsTest.php @@ -0,0 +1,50 @@ +addParagraphedContentType('paragraphed_test', 'field_paragraphs'); + $this->loginAsAdmin(['create paragraphed_test content', 'edit any paragraphed_test content']); + + // Add a Paragraph type. + $paragraph_type = 'text_paragraph'; + $this->addParagraphsType($paragraph_type); + + // Add a text field to the text_paragraph type. + static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []); + + // Enable the test plugin. + $edit = [ + 'feature_plugins[test_feature_plugin][enabled]' => TRUE, + ]; + $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save')); + + // Create a node with a Paragraph. + $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more'); + $plugin_text = 'plugin_field_text'; + $edit = [ + 'title[0][value]' => 'paragraphs_plugins_test', + 'field_paragraphs[0][subform][field_text][0][value]' => 'amazing_plugin_test', + 'field_paragraphs[0][feature][test_feature_plugin][test_field]' => $plugin_text, + ]; + $this->drupalPostForm(NULL, $edit, t('Save and publish')); + $this->clickLink('Edit'); + // Assert the plugin fields populate the stored values. + $this->assertFieldByName('field_paragraphs[0][feature][test_feature_plugin][test_field]', $plugin_text); + } + +} diff --git a/src/Tests/ParagraphsTestBase.php b/src/Tests/ParagraphsTestBase.php index 614c60a..9508aaa 100644 --- a/src/Tests/ParagraphsTestBase.php +++ b/src/Tests/ParagraphsTestBase.php @@ -43,6 +43,7 @@ abstract class ParagraphsTestBase extends WebTestBase { 'field', 'field_ui', 'block', + 'paragraphs_test', ]; /** diff --git a/tests/modules/paragraphs_test/paragraphs_test.info.yml b/tests/modules/paragraphs_test/paragraphs_test.info.yml new file mode 100644 index 0000000..f91e94e --- /dev/null +++ b/tests/modules/paragraphs_test/paragraphs_test.info.yml @@ -0,0 +1,9 @@ +name: Paragraphs test +type: module +description: Resources for Paragraphs tests +core: 8.x +hidden: true +package: Paragraphs + +dependencies: + - paragraphs diff --git a/tests/modules/paragraphs_test/src/Plugin/paragraphs_type/Feature/TestFeaturePlugin.php b/tests/modules/paragraphs_test/src/Plugin/paragraphs_type/Feature/TestFeaturePlugin.php new file mode 100644 index 0000000..d64a1a0 --- /dev/null +++ b/tests/modules/paragraphs_test/src/Plugin/paragraphs_type/Feature/TestFeaturePlugin.php @@ -0,0 +1,30 @@ + 'textfield', + '#title' => $this->t('Label'), + '#maxlength' => 255, + '#default_value' => $paragraphs_entity->getFeatureSettings([$this->getPluginId(), 'test_field']), + '#description' => $this->t("Label for the Paragraphs type."), + ]; + return $form; + } + +}