diff --git a/core/includes/entity.inc b/core/includes/entity.inc index 8cb009a6357ba9e78f601d0a1260a6e8d0759175..bdc89f1a89f31a67fd04bc8831d9d836558c2236 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -454,7 +454,7 @@ function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_st // this form. Copying field values must be done using field_attach_submit(). $values_excluding_fields = $info['fieldable'] ? array_diff_key($form_state['values'], field_info_instances($entity_type, $entity->bundle())) : $form_state['values']; foreach ($values_excluding_fields as $key => $value) { - $entity->$key = $value; + $entity->set($key, $value); } // Invoke all specified builders for copying form values to entity properties. diff --git a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php index 3f39af80145b07ef2555005849eb57075ccc93df..29be1f6c4cf61e689203b058945abcabbaefed82 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php +++ b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php @@ -26,7 +26,8 @@ * form_controller_class = { * "edit" = "Drupal\views_ui\ViewEditFormController", * "add" = "Drupal\views_ui\ViewAddFormController", - * "preview" = "Drupal\views_ui\ViewPreviewFormController" + * "preview" = "Drupal\views_ui\ViewPreviewFormController", + * "clone" = "Drupal\views_ui\ViewCloneFormController" * }, * config_prefix = "views.view", * fieldable = FALSE, diff --git a/core/modules/views/lib/Drupal/views/Tests/UI/DefaultViewsTest.php b/core/modules/views/lib/Drupal/views/Tests/UI/DefaultViewsTest.php index 770f1bf619a46e85ea9518d7cd488a913df46774..a274311f1bfb24ffb52b7b4467e86ef8eb61a7f1 100644 --- a/core/modules/views/lib/Drupal/views/Tests/UI/DefaultViewsTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/UI/DefaultViewsTest.php @@ -73,6 +73,23 @@ function testDefaultViews() { // $this->drupalGet('frontpage'); // $this->assertNoText($new_title); + // Clone the view and check that the normal schema of cloned views is used. + $this->drupalGet('admin/structure/views'); + $this->clickViewsOperationLink(t('Clone'), '/frontpage'); + $edit = array( + 'name' => 'clone_of_frontpage', + ); + $this->assertTitle(t('Clone of @human_name | @site-name', array('@human_name' => 'Front page', '@site-name' => config('system.site')->get('name')))); + $this->drupalPost(NULL, $edit, t('Clone')); + $this->assertUrl('admin/structure/views/view/clone_of_frontpage/edit', array(), 'The normal cloning name schema is applied.'); + + // Clone a view and set a custom name. + $this->drupalGet('admin/structure/views'); + $this->clickViewsOperationLink(t('Clone'), '/frontpage'); + $random_name = strtolower($this->randomName()); + $this->drupalPost(NULL, array('name' => $random_name), t('Clone')); + $this->assertUrl("admin/structure/views/view/$random_name/edit", array(), 'The custom view name got saved.'); + // Now disable the view, and make sure it stops appearing on the main view // listing page but instead goes back to displaying on the disabled views // listing page. @@ -126,7 +143,7 @@ function clickViewsOperationLink($label, $unique_href_part) { break; } } - $this->assertTrue(isset($index), t('Link to "@label" containing @part found.', array('@label' => $label, '@part' => $unique_href_part))); + $this->assertTrue(isset($index), format_string('Link to "@label" containing @part found.', array('@label' => $label, '@part' => $unique_href_part))); if (isset($index)) { return $this->clickLink($label, $index); } diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewCloneFormController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewCloneFormController.php new file mode 100644 index 0000000000000000000000000000000000000000..70f18a932ffbf3c2ba3e4ce420b1bf8f13780e44 --- /dev/null +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewCloneFormController.php @@ -0,0 +1,80 @@ +<?php + +/** + * @file + * Contains \Drupal\views_ui\ViewCloneFormController. + */ + +namespace Drupal\views_ui; + +use Drupal\Core\Entity\EntityInterface; + +/** + * Form controller for the Views clone form. + */ +class ViewCloneFormController extends ViewFormControllerBase { + + /** + * Overrides \Drupal\Core\Entity\EntityFormController::prepareForm(). + */ + protected function prepareEntity(EntityInterface $entity) { + // Do not prepare the entity while it is being added. + } + + /** + * Overrides \Drupal\Core\Entity\EntityFormController::form(). + */ + public function form(array $form, array &$form_state, EntityInterface $entity) { + parent::form($form, $form_state, $entity); + + $form['human_name'] = array( + '#type' => 'textfield', + '#title' => t('View name'), + '#required' => TRUE, + '#size' => 32, + '#default_value' => '', + '#maxlength' => 255, + '#default_value' => t('Clone of @human_name', array('@human_name' => $entity->getHumanName())), + ); + $form['name'] = array( + '#type' => 'machine_name', + '#maxlength' => 128, + '#machine_name' => array( + 'exists' => 'views_get_view', + 'source' => array('human_name'), + ), + '#default_value' => '', + '#description' => t('A unique machine-readable name for this View. It must only contain lowercase letters, numbers, and underscores.'), + ); + + return $form; + } + + /** + * Overrides \Drupal\Core\Entity\EntityFormController::actions(). + */ + protected function actions(array $form, array &$form_state) { + $actions['submit'] = array( + '#value' => t('Clone'), + '#submit' => array( + array($this, 'submit'), + ), + ); + return $actions; + } + + /** + * Overrides \Drupal\Core\Entity\EntityFormController::form(). + */ + public function submit(array $form, array &$form_state) { + $entity = parent::submit($form, $form_state); + $entity->setOriginalID(NULL); + $entity->save(); + + // Redirect the user to the view admin form. + $uri = $entity->uri(); + $form_state['redirect'] = $uri['path'] . '/edit'; + return $entity; + } + +} diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewListController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewListController.php index ac8dc4ea296f9125c77ad380bbff8ad0255b9413..a3e2bea4c224bf79ebdc49949ba9710d82c463b4 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewListController.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewListController.php @@ -123,6 +123,12 @@ public function getOperations(EntityInterface $view) { 'weight' => 10, ); } + $definition['clone'] = array( + 'title' => t('Clone'), + 'href' => "$path/clone", + 'weight' => 15, + ); + return $definition; } diff --git a/core/modules/views/views_ui/views_ui.module b/core/modules/views/views_ui/views_ui.module index feb6553b44ba8d2b43ad09ede509c62509606709..b7040acda179a3687736f08b384137ccc449f296 100644 --- a/core/modules/views/views_ui/views_ui.module +++ b/core/modules/views/views_ui/views_ui.module @@ -6,6 +6,7 @@ */ use Drupal\views\ViewExecutable; +use Drupal\views\Plugin\Core\Entity\View; use Drupal\views_ui\ViewUI; use Drupal\views\Analyzer; use Drupal\Core\Entity\EntityInterface; @@ -49,6 +50,14 @@ function views_ui_menu() { 'type' => MENU_DEFAULT_LOCAL_TASK, ) + $base; + $items['admin/structure/views/view/%views_ui_cache/clone'] = array( + 'title callback' => 'views_ui_clone_title', + 'title arguments' => array(4), + 'page callback' => 'entity_get_form', + 'page arguments' => array(4, 'clone'), + 'type' => MENU_CALLBACK, + ) + $base; + $items['admin/structure/views/view/%views_ui/enable'] = array( 'title' => 'Enable a view', ) + $ajax_base; @@ -373,6 +382,16 @@ function views_ui_cache_set(ViewUI $view) { drupal_container()->get('user.tempstore')->get('views')->set($view->get('name'), $view); } +/** + * Title callback for the views clone form. + * + * @param \Drupal\views\ViewExecutable $view + * The view to clone. + */ +function views_ui_clone_title(ViewUI $view) { + return t('Clone of @human_name', array('@human_name' => $view->getHumanName())); +} + /** * Theme preprocess for views-view.tpl.php. */