diff --git a/tripal/src/Entity/TripalEntity.php b/tripal/src/Entity/TripalEntity.php index b5369c4dde..b139d8f0a7 100755 --- a/tripal/src/Entity/TripalEntity.php +++ b/tripal/src/Entity/TripalEntity.php @@ -33,6 +33,7 @@ * "add" = "Drupal\tripal\Form\TripalEntityForm", * "edit" = "Drupal\tripal\Form\TripalEntityForm", * "delete" = "Drupal\tripal\Form\TripalEntityDeleteForm", + * "unpublish" = "Drupal\tripal\Form\TripalEntityUnpublishForm", * }, * "access" = "Drupal\tripal\Access\TripalEntityAccessControlHandler", * "route_provider" = { @@ -52,6 +53,7 @@ * "add-form" = "/bio_data/add/{tripal_entity_type}", * "edit-form" = "/bio_data/{tripal_entity}/edit", * "delete-form" = "/bio_data/{tripal_entity}/delete", + * "unpublish-form" = "/bio_data/{tripal_entity}/unpublish", * "collection" = "/admin/content/bio_data", * }, * bundle_entity_type = "tripal_entity_type", @@ -668,4 +670,30 @@ public function validate() { return $violations; } + + /** + * Performs a removal of the entity from Drupal. + * + * This function copies the code from the parent::delete() function. It + * does not remove the record from the storage backend. The + * postDelete() function will be triggered. + */ + public function unpublish() { + parent::delete(); + } + + /** + * Performs a total remove of the record from Drupal and the DB backend. + * + * This function copies the code from the parent::delete() function but + * then performs extra steps to delete the record in the database backend. + * The postDelete() function will also be triggered because it uses the + * parent::delete() function to delete the entity from Drupal. + */ + public function delete() { + parent::delete(); + // @todo: add in code to remove entity from the database backend. + } + + } diff --git a/tripal/src/Form/TripalEntityDeleteForm.php b/tripal/src/Form/TripalEntityDeleteForm.php index d393c74635..8a8312d78a 100755 --- a/tripal/src/Form/TripalEntityDeleteForm.php +++ b/tripal/src/Form/TripalEntityDeleteForm.php @@ -3,6 +3,8 @@ namespace Drupal\tripal\Form; use Drupal\Core\Entity\ContentEntityDeleteForm; +use Drupal\Core\Form\FormStateInterface; + /** * Provides a form for deleting Tripal Content entities. @@ -11,5 +13,26 @@ */ class TripalEntityDeleteForm extends ContentEntityDeleteForm { + /** + * {@inheritdoc} + */ + public function getQuestion() { + return $this->t('Are you sure you want to unpublish and permanenty ' + . 'delete %name?', ['%name' => $this->entity->label()]); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Delete'); + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->t('This action is not fully implemented in Tripal v4. It currently functions as an"unpublish".'); + } } diff --git a/tripal/src/Form/TripalEntityForm.php b/tripal/src/Form/TripalEntityForm.php index 4b9ed69814..355755d8da 100755 --- a/tripal/src/Form/TripalEntityForm.php +++ b/tripal/src/Form/TripalEntityForm.php @@ -5,6 +5,7 @@ use Drupal\Core\Entity\ContentEntityForm; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Messenger\MessengerTrait; +use Drupal\Component\Serialization\Json; /** * Form controller for Tripal Content edit forms. @@ -57,4 +58,42 @@ public function save(array $form, FormStateInterface $form_state) { $form_state->setRedirect('entity.tripal_entity.canonical', ['tripal_entity' => $entity->id()]); } + /** + * + * {@inheritDoc} + * @see \Drupal\Core\Entity\EntityForm::actions() + */ + protected function actions(array $form, FormStateInterface $form_state) { + $actions = parent::actions($form, $form_state); + if (!$this->entity->isNew() && $this->entity->hasLinkTemplate('unpublish-form')) { + $route_info = $this->entity->toUrl('canonical'); + $actions['cancel'] = [ + '#type' => 'link', + '#title' => $this->t('Cancel'), + '#access' => $this->entity->access('administer tripal content'), + '#attributes' => [ + 'class' => ['button'], + ], + '#url' => $route_info, + ]; + $route_info = $this->entity->toUrl('unpublish-form'); + $actions['unpublish'] = [ + '#type' => 'link', + '#title' => $this->t('Unpublish'), + '#access' => $this->entity->access('administer tripal content'), + '#attributes' => [ + 'class' => ['button', 'button--danger', 'use-ajax'], + 'data-dialog-type' => 'modal', + 'data-dialog-options' => Json::encode([ + 'width' => 880, + ]), + ], + '#url' => $route_info, + '#attached' => [ + 'library' => ['core/drupal.dialog.ajax'], + ], + ]; + } + return $actions; + } } diff --git a/tripal/src/Form/TripalEntityUnpublishForm.php b/tripal/src/Form/TripalEntityUnpublishForm.php new file mode 100644 index 0000000000..88793cfaa2 --- /dev/null +++ b/tripal/src/Form/TripalEntityUnpublishForm.php @@ -0,0 +1,82 @@ +t('Are you sure you want to unpublish %name?', + ['%name' => $this->entity->label()]); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Unpublish'); + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->t('Unpublishing will remove this page from the site but the data ' + . 'will be retained in the database and you can republish it again later if desired.'); + } + + /** + * Similar to the parent::getDeleteMessage() but custom for unpublishing. + */ + protected function getUnpublishMessage() { + $entity = $this->getEntity(); + return $this->t('The @entity-type %label has been unpublished.', [ + '@entity-type' => $entity->getEntityType()->getSingularLabel(), + '%label' => $entity->label() ?? $entity->id(), + ]); + } + + /** + * Similar to the parent::logUnpublishMessage() but custom for unpublishing. + */ + protected function logUnpublishMessage() { + /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ + $entity = $this->getEntity(); + $this->logger($entity->getEntityType()->getProvider())->info('The @entity-type %label has been unpublished.', [ + '@entity-type' => $entity->getEntityType()->getSingularLabel(), + '%label' => $entity->label(), + ]); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + /** @var \Drupal\tripal\Entity\TripalEntity $entity */ + $entity = $this->getEntity(); + $message = $this->getUnpublishMessage(); + + $entity->unpublish(); + $form_state->setRedirectUrl($this->getRedirectUrl()); + + $this->messenger()->addStatus($message); + $this->logUnpublishMessage(); + } + + + +} diff --git a/tripal/src/ListBuilders/TripalEntityListBuilder.php b/tripal/src/ListBuilders/TripalEntityListBuilder.php index 109c2a0f47..d5a9ccf67c 100755 --- a/tripal/src/ListBuilders/TripalEntityListBuilder.php +++ b/tripal/src/ListBuilders/TripalEntityListBuilder.php @@ -7,6 +7,7 @@ use Drupal\Core\Link; use Drupal\Core\Url; use Drupal\Component\Render\FormattableMarkup; +use Drupal\Component\Serialization\Json; use Drupal\Component\Utility\Xss; /** @@ -89,6 +90,29 @@ public function load() { } } + /** + * {@inheritDoc} + * @see \Drupal\Core\Entity\EntityListBuilder::getDefaultOperations() + */ + protected function getDefaultOperations(EntityInterface $entity) { + $operations = parent::getDefaultOperations($entity); + + if ($entity->access('unpublish') && $entity->hasLinkTemplate('unpublish-form')) { + $operations['unpublish'] = [ + 'title' => $this->t('Unpublish'), + 'weight' => 59, + 'attributes' => [ + 'class' => ['use-ajax'], + 'data-dialog-type' => 'modal', + 'data-dialog-options' => Json::encode([ + 'width' => 880, + ]), + ], + 'url' => $this->ensureDestination($entity->toUrl('unpublish-form')), + ]; + } + return $operations; + } } diff --git a/tripal/src/Routing/TripalEntityHtmlRouteProvider.php b/tripal/src/Routing/TripalEntityHtmlRouteProvider.php index 001744589a..6b9d447b73 100755 --- a/tripal/src/Routing/TripalEntityHtmlRouteProvider.php +++ b/tripal/src/Routing/TripalEntityHtmlRouteProvider.php @@ -25,10 +25,43 @@ public function getRoutes(EntityTypeInterface $entity_type) { if ($collection_route = $this->getCollectionRoute($entity_type)) { $collection->add("entity.{$entity_type_id}.collection", $collection_route); } + if ($unpublish_route = $this->getUnpublishRoute($entity_type)) { + $collection->add("entity.{$entity_type_id}.unpublish", $unpublish_route); + } return $collection; } + /** + * Gets the unpublish route. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type. + * + * @return \Symfony\Component\Routing\Route|null + * The generated route, if available. + */ + protected function getUnpublishRoute(EntityTypeInterface $entity_type) { + + if ($entity_type->hasLinkTemplate('unpublish-form')) { + $entity_type_id = $entity_type->id(); + $route = new Route($entity_type->getLinkTemplate('unpublish-form')); + $route->addDefaults([ + '_entity_form' => "{$entity_type_id}.unpublish", + '_title_callback' => '\Drupal\Core\Entity\Controller\EntityController::deleteTitle', + ])->setRequirement('_entity_access', "{$entity_type_id}.unpublish") + ->setOption('parameters', [$entity_type_id => ['type' => 'entity:' . $entity_type_id], + ]); + + // Entity types with serial IDs can specify this in their route + // requirements, improving the matching process. + if ($this->getEntityTypeIdKeyType($entity_type) === 'integer') { + $route->setRequirement($entity_type_id, '\d+'); + } + return $route; + } + } + /** * Gets the collection route. * diff --git a/tripal/tests/src/Functional/Permissions/TripalRoutePermissionsTest.php b/tripal/tests/src/Functional/Permissions/TripalRoutePermissionsTest.php index 09bf7943c1..0a577575e8 100644 --- a/tripal/tests/src/Functional/Permissions/TripalRoutePermissionsTest.php +++ b/tripal/tests/src/Functional/Permissions/TripalRoutePermissionsTest.php @@ -272,6 +272,7 @@ public function testTripalContentPages() { 'entity-add-form' => 'bio_data/add/' . $content_type, 'entity-edit-form' => 'bio_data/' . $entity_id . '/edit', 'entity-delete-form' => 'bio_data/' . $entity_id . '/delete', + 'entity-unpublish-form' => 'bio_data/' . $entity_id . '/unpublish', 'entity-collection' => 'admin/content/bio_data', //'publish-content' => '', 'unpublish-content' => 'admin/content/bio_data/unpublish', @@ -294,7 +295,10 @@ public function testTripalContentPages() { 'edit tripal content entities' => ['entity-edit-form'], 'delete tripal content entities' => ['entity-delete-form'], 'view tripal content entities' => ['entity-canonical'], - 'administer tripal content' => ['entity-canonical', 'entity-add-page', 'entity-add-form', 'entity-edit-form', 'entity-delete-form', 'entity-collection', 'publish-content', 'unpublish-content'], + 'administer tripal content' => ['entity-canonical', 'entity-add-page', + 'entity-add-form', 'entity-edit-form', 'entity-delete-form', + 'entity-collection', 'publish-content', 'unpublish-content', + 'entity-unpublish-form'], 'manage tripal content types' => ['entitytype-add-form', 'entitytype-edit-form', 'entitytype-delete-form', 'entitytype-collection'], 'administer tripal_entity fields' => ['entitytype-manage-fields'], 'administer tripal_entity form display' => ['entitytype-manage-form'], diff --git a/tripal/tripal.links.task.yml b/tripal/tripal.links.task.yml index ff043b8fc4..2649adb399 100755 --- a/tripal/tripal.links.task.yml +++ b/tripal/tripal.links.task.yml @@ -25,6 +25,13 @@ entity.tripal_entity.delete_form: route_name: entity.tripal_entity.delete_form base_route: entity.tripal_entity.canonical title: Delete + weight: 20 + +# -- Provides an Unpublish task link on each Tripal content page. +entity.tripal_entity.unpublish_form: + route_name: entity.tripal_entity.unpublish_form + base_route: entity.tripal_entity.canonical + title: Unpublish weight: 10 ## diff --git a/tripal/tripal.routing.yml b/tripal/tripal.routing.yml index 9234ca9347..b7ce959e08 100644 --- a/tripal/tripal.routing.yml +++ b/tripal/tripal.routing.yml @@ -187,6 +187,19 @@ tripal.content_type_field_check: requirements: _permission: 'administer tripal' +# Adds an unpublished link to Tripal entity pages. +entity.tripal_entity.unpublish_form: + path: 'bio_data/{tripal_entity}/unpublish' + defaults: + _form: '\Drupal\tripal\Form\TripalEntityUnpublishForm' + _title: 'Unpublish' + options: + parameters: + tripal_entity: + type: entity:tripal_entity + requirements: + _permission: 'administer tripal content' + ## # Controlled Vocabularies. ##