monster_menus-9.0.x-dev/src/Form/CopyMoveContentForm.php
src/Form/CopyMoveContentForm.php
<?php
namespace Drupal\monster_menus\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Database\Connection;
use Drupal\monster_menus\Constants;
use Drupal\node\Entity\Node;
use Symfony\Component\DependencyInjection\ContainerInterface;
class CopyMoveContentForm extends FormBase {
/**
* Database Service Object.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'mm_ui_content_copymove';
}
/**
* Constructs an object.
*/
public function __construct(Connection $database) {
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('database'));
}
public function buildForm(array $form, FormStateInterface $form_state) {
$item = $form_state->getBuildInfo()['args'][0];
$x = mm_ui_strings($is_group = $item->is_group);
if ($item->parent > 0) {
$pitem = mm_content_get_tree($item->parent, [
Constants::MM_GET_TREE_DEPTH => 0,
Constants::MM_GET_TREE_RETURN_PERMS => TRUE,
]);
}
$form['#attributes'] = ['class' => ['mm-ui-copymove']];
$form['mmtid'] = [
'#type' => 'value',
'#value' => $item->mmtid,
];
$form['mode'] = [
'#type' => 'details',
'#title' => $this->t('Mode'),
'#open' => TRUE,
];
$form['mode']['mode'] = [
'#type' => 'radios',
'#default_value' => 'copy',
'#options' => ['copy' => $this->t('Copy'), 'move' => $this->t('Move')],
];
$form['copy'] = [
'#type' => 'details',
'#attributes' => ['id' => 'copydiv'],
'#title' => $this->t('What to copy'),
'#open' => TRUE,
];
$mustcheck = $is_group ? '' : $this->t('You must choose "This @thing", "Contents", or both.', $x);
$form['copy']['copy_page'] = [
'#type' => 'checkbox',
'#default_value' => TRUE,
'#title' => $this->t('This @thing', $x),
];
$form['copy']['copy_subpage'] = [
'#type' => 'checkbox',
'#default_value' => FALSE,
'#attributes' => ['style' => 'margin-left: 20px'],
'#title' => $this->t('and any @subthings', $x),
];
if (!$is_group) {
$form['copy']['copy_nodes'] = [
'#type' => 'checkbox',
'#default_value' => FALSE,
'#title' => $this->t('Contents'),
];
$form['copy']['desc'] = [
'#type' => 'item',
'#input' => FALSE,
'#description' => $this->t('When contents are copied without their current @thing, the new copies take on the permissions of the destination @thing.', $x),
];
}
$form['move'] = [
'#type' => 'details',
'#attributes' => ['id' => 'movediv'],
'#title' => $this->t('What to move'),
'#open' => TRUE,
];
$form['move']['move_mode'] = [
'#type' => 'radios',
'#default_value' => 'page',
'#description' => $is_group ? NULL : $this->t('Moved contents keep their original permissions.'),
'#options' => [
'page' => $this->t($is_group ? 'This @thing and any @subthings' : 'This @thing, any @subthings, and all their contents', $x),
'nodes' => $this->t('Just the contents appearing on this @thing', $x),
],
];
$limit_move = isset($item->flags['limit_move']) && !$this->currentUser()->hasPermission('administer all menus');
if ($is_group) {
unset($form['move']['move_mode']['#options']['nodes']);
if ($limit_move) {
unset($form['mode']['mode']['#options']['move']);
$form['mode']['mode']['#description'] = $this->t('You are not allowed to move this group.') . ' ' . $form['mode']['mode']['#description'];
}
elseif (mm_content_is_vgroup($item->mmtid)) {
$form['mode']['mode']['#default_value'] = 'move';
unset($form['mode']['mode']['#options']['copy']);
}
}
elseif ($item->perms[Constants::MM_PERMS_IS_RECYCLED]) {
unset($form['mode']['mode']['#options']['move']);
$form['mode']['mode']['#description'] = $this->t('This @thing is in the recycle bin. You can copy it, but it cannot be moved.', $x);
}
elseif ($limit_move) {
$form['move']['move_mode']['#default_value'] = 'nodes';
unset($form['move']['move_mode']['#options']['page']);
$form['move']['move_mode']['#description'] = $this->t('You are not allowed to move this page, only its contents.') . ' ' . $form['move']['move_mode']['#description'];
}
else {
$prevent_mode = mm_get_setting('prevent_showpage_removal');
if ($prevent_mode != Constants::MM_PREVENT_SHOWPAGE_REMOVAL_NONE && ($showpage_mmtid = mm_content_test_showpage_mmtid($item->mmtid))) {
if ($prevent_mode == Constants::MM_PREVENT_SHOWPAGE_REMOVAL_WARN || $this->currentUser()->hasPermission('administer all menus')) {
$form['move']['move_mode']['#description'] = $showpage_mmtid == $item->mmtid ?
$this->t('<strong>Warning:</strong> This page contains dynamic content which may no longer appear if it is moved to another location.') :
$this->t('<strong>Warning:</strong> The sub-page <a href=":link">@title</a> contains dynamic content which may no longer appear if this page is moved to another location.', ['@title' => mm_content_get_name($showpage_mmtid), ':link' => mm_content_get_mmtid_url($showpage_mmtid)->toString()]);
}
else {
$form['move']['move_mode']['#default_value'] = 'nodes';
unset($form['move']['move_mode']['#options']['page']);
$form['move']['move_mode']['#description'] = $showpage_mmtid == $item->mmtid ?
$this->t('This page contains dynamic content which will no longer appear if it is moved to another location. You may only move the contents.') :
$this->t('The sub-page <a href=":link">@title</a> contains dynamic content which will no longer appear if this page is moved to another location. You may only move the contents.', ['@title' => mm_content_get_name($showpage_mmtid), ':link' => mm_content_get_mmtid_url($showpage_mmtid)->toString()]);
}
}
}
$form['dest'] = [
'#type' => 'details',
'#title' => $this->t('Destination'),
'#open' => TRUE,
];
$parents = mm_content_get_parents($item->mmtid);
// skip root
if (!$this->currentUser()->hasPermission('administer all menus')) {
array_shift($parents);
}
$pop_start = implode('/', $parents) . "/$item->mmtid";
$form['dest']['dest'] = [
'#title' => $this->t('Destination'),
'#type' => $is_group ? 'mm_grouplist' : 'mm_catlist',
'#required' => $item->parent <= 0,
'#default_value' => isset($pitem) ?
[$pitem[0]->mmtid => mm_content_get_name($pitem[0])] :
['' => $this->t('(choose the destination)')],
'#mm_list_popup_start' => $pop_start,
'#mm_list_min' => 1,
'#mm_list_max' => 1,
'#mm_list_selectable' => Constants::MM_PERMS_SUB . Constants::MM_PERMS_APPLY,
'#description' => $this->t('Choose where to copy/move the @thing. The default value is the @thingpos current parent.', $x),
];
$form['name_alias'] = [
'#type' => 'details',
'#attributes' => ['id' => 'namediv'],
'#title' => $is_group ? $this->t('Name') : $this->t('Name and URL name'),
'#open' => TRUE,
];
$form['name_alias']['name'] = [
'#type' => 'textfield',
'#title' => $this->t('New @thing name', $x),
'#default_value' => $item->name,
'#size' => 40,
'#maxlength' => 128,
'#description' => $this->t('If you do not change the Destination above, you must modify the page name and URL name here.'),
'#states' => [
// Add a state which is triggered from copymove.js.
'required' => ["#namediv" => ['required' => TRUE]],
],
];
if (!$is_group) {
$form['name_alias']['alias'] = [
'#type' => 'machine_name',
'#machine_name' => [
'exists' => 'mm_ui_machine_name_exists',
'source' => ['name_alias', 'name'],
'label' => $this->t('New URL name'),
'replace_pattern' => '[^-.\w]+',
'replace' => '-',
'error' => $this->t('The URL name must contain only letters, numerals, hyphens, periods and underscores.'),
'standalone' => TRUE,
],
'#title' => $this->t('New URL name'),
'#default_value' => $item->alias,
'#size' => 20,
'#maxlength' => 128,
'#description' => $this->t('The name that will be used in the Web address of the page. ' .
'Make this a shortened version of the Page name, using only lowercase letters, ' .
'numerals, hyphens, periods and underscores.'),
];
if (empty($item->is_user_home) && !$this->currentUser()->hasPermission('administer all menus')) {
// Add a state which is triggered from copymove.js.
$form['name_alias']['alias']['#states'] = [
'required' => ["#namediv" => ['required' => TRUE]],
];
}
}
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Go!'),
'#button_type' => 'primary',
];
mm_static($form, 'copymove', $mustcheck);
return $form;
}
public static function validate(array &$form, FormStateInterface $form_state, $restore) {
$form_values =& $form_state->getValues();
self::getValues($form_values, $src_mmtid, $modes, $src_parent_mmtid, $dest_mmtid);
$nodes_only = $modes['move_nodes'] || $modes['copy_nodes'] && !$modes['copy_page'];
if (!$restore && ($modes['copy_page'] || $modes['move_page'])) {
mm_ui_validate_sometimes_required($form['name_alias']['name'], trim($form_values['name']), $form_state);
if (isset($form['name_alias']['alias'])) {
mm_ui_validate_sometimes_required($form['name_alias']['alias'], trim($form_values['alias']), $form_state);
}
}
if (!$src_mmtid || !is_numeric($src_mmtid)) {
$form_state->setErrorByName('', t('Missing one or more required fields'));
return;
}
$x = mm_ui_strings(mm_content_is_group($src_mmtid));
if ($modes['move_page'] && !mm_content_user_can($src_mmtid, Constants::MM_PERMS_WRITE)) {
$message = t('You do not have permission to modify this @thing.', $x);
}
if ($modes['move_page'] && !$restore && !mm_content_user_can($src_parent_mmtid, Constants::MM_PERMS_SUB)) {
$message = t('You do not have permission to modify the source @thingpos parent.', $x);
}
if (!is_numeric($dest_mmtid) || !mm_content_user_can($dest_mmtid, $nodes_only ? Constants::MM_PERMS_APPLY : Constants::MM_PERMS_SUB)) {
$message = t('You do not have permission to modify the destination @thing.', $x);
}
if (mm_content_is_normal($src_mmtid) != ($dest_mmtid == 1 || mm_content_is_normal($dest_mmtid)) || mm_content_is_group($src_mmtid) != mm_content_is_group($dest_mmtid)) {
$message = t('Source and destination are not of the same type.');
}
if (mm_content_user_can($dest_mmtid, Constants::MM_PERMS_IS_RECYCLED)) {
if ($modes['copy_nodes'] || $modes['copy_page']) {
$message = t('You cannot copy to a recycle bin.');
}
else {
$message = t('You cannot move to a recycle bin using this option. Please use the Delete option, instead.');
}
}
if (!empty($message)) {
\Drupal::logger('mm')->warning($message, []);
$form_state->setErrorByName('', $message);
return;
}
if (mm_content_is_vgroup($src_mmtid) != mm_content_is_vgroup($dest_mmtid)) {
$form_state->setErrorByName('dest', mm_content_is_vgroup($src_mmtid) ? t('Pre-defined groups can only be moved to create sub-groups of other pre-defined groups.') : t('You cannot copy/move a regular group inside the pre-defined groups list.'));
}
if (!$nodes_only && !_mm_ui_validate_entry($src_mmtid, $dest_mmtid, $form_state, $form_values, TRUE)) {
return;
}
if ($dest_mmtid == $src_parent_mmtid && $modes['move_page']) {
$form_state->setErrorByName('', t('Instead of moving a @thing within the same parent @thing, rename it using Settings->Edit.', $x));
}
elseif ($dest_mmtid == $src_mmtid && $nodes_only && $modes['move_nodes']) {
$form_state->setErrorByName('', t('Moving just a @thingpos contents to itself results in no change.', $x));
}
elseif ($dest_mmtid == $src_mmtid && !$modes['move_nodes'] && ($modes['move_page'] || $modes['copy_recur'])) {
$form_state->setErrorByName('', t('You cannot copy or move a @thing within itself.', $x));
}
elseif (mm_content_is_child($dest_mmtid, $src_mmtid)) {
if ($modes['move_page']) {
$form_state->setErrorByName('dest', t('You cannot move a @thing into a @subthing of itself. Please choose another destination.', $x));
}
elseif ($modes['copy_recur']) {
$form_state->setErrorByName('dest', t('You cannot copy a @thing and any @subthings into a child of itself. Please choose another destination.', $x));
}
}
elseif ($modes['move_nodes'] && mm_content_is_archive($dest_mmtid)) {
$form_state->setErrorByName('dest', t('You cannot move content into an archive. Move the content into the main @thing, instead, and the archive will be updated automatically.', $x));
}
}
public function validateForm(array &$form, FormStateInterface $form_state) {
self::validate($form, $form_state, FALSE);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$form_values =& $form_state->getValues();
self::getValues($form_values, $src_mmtid, $modes, $src_parent_mmtid, $dest_mmtid);
$name = trim($form_values['name']);
$alias = isset($form_values['alias']) ? trim($form_values['alias']) : NULL;
$x = mm_ui_strings(mm_content_is_group($src_mmtid));
if ($modes['copy_page'] || $modes['copy_nodes']) {
if ($modes['copy_page'] && $modes['copy_nodes']) {
$msg = $modes['copy_recur'] ?
$this->t('The @thing, any @subthings, and their contents were successfully copied.', $x) :
$this->t('The @thing and its contents were successfully copied.', $x);
}
elseif ($modes['copy_nodes']) {
$msg = $this->t('The @thingpos contents were successfully copied.', $x);
}
else {
$msg = $modes['copy_recur'] ?
$this->t('The @thing and any @subthings were successfully copied.', $x) :
$this->t('The @thing was successfully copied.', $x);
}
$copy_params = [
Constants::MM_COPY_ALIAS => $alias,
Constants::MM_COPY_CONTENTS => $modes['copy_nodes'],
Constants::MM_COPY_NAME => $name,
Constants::MM_COPY_OWNER => $this->currentUser()->id(),
Constants::MM_COPY_READABLE => TRUE,
Constants::MM_COPY_RECUR => $modes['copy_recur'],
Constants::MM_COPY_TREE => $modes['copy_page'],
];
$new_mmtid = mm_content_copy($src_mmtid, $dest_mmtid, $copy_params);
if (is_numeric($new_mmtid)) {
if ($new_mmtid != $src_mmtid) {
$msg .= ' ' . $this->t('You are now viewing the destination.');
}
$this->messenger()->addStatus($msg);
mm_set_form_redirect_to_mmtid($form_state, $new_mmtid);
}
else {
$this->messenger()->addError($this->t($new_mmtid));
}
}
elseif ($modes['move_page']) {
$old_tree = mm_content_get($src_mmtid);
$error = mm_content_move($src_mmtid, $dest_mmtid, '');
if (!$error) {
if ($name != $old_tree->name || $alias != $old_tree->alias) {
mm_content_update_quick(['name' => $name, 'alias' => $alias], ['mmtid' => $src_mmtid], $dest_mmtid);
}
$this->messenger()->addStatus($this->t('The @thing was successfully moved.', $x));
mm_set_form_redirect_to_mmtid($form_state, $src_mmtid);
}
else {
$this->messenger()->addError($this->t($error));
}
}
elseif ($modes['move_nodes']) {
$total = 0;
$ok = [];
foreach (mm_content_get_nids_by_mmtid($src_mmtid) as $nid) {
$total++;
$uid = $this->database->select('node_field_data', 'n')
->fields('n', ['uid'])
->condition('n.nid', $nid)
->execute()->fetchField();
if (!empty($uid) || $uid === 0) {
/** @var \Drupal\node\Entity\Node $node */
$node = Node::load($nid);
$node->setOwnerId($uid);
if (mm_content_node_access($node, 'update')) {
// If node already appears on both $src_mmtid and $dest_mmtid, just
// remove entry from mm_node2tree. Unfortunately, merge() and
// upsert() do not handle this case.
if ($this->database->select('mm_node2tree')
->condition('mmtid', $dest_mmtid)
->condition('nid', $nid)
->countQuery()
->execute()->fetchField()) {
$this->database->delete('mm_node2tree')
->condition('mmtid', $src_mmtid)
->condition('nid', $nid)
->execute();
}
else {
$this->database->update('mm_node2tree')
->fields(['mmtid' => $dest_mmtid])
->condition('mmtid', $src_mmtid)
->condition('nid', $nid)
->execute();
}
mm_content_reset_custom_node_order($dest_mmtid, $nid);
$ok[] = $nid;
}
}
mm_content_clear_node_cache($ok);
mm_content_notify_change('move_node', NULL, $ok, ['old_mmtid' => $src_mmtid, 'new_mmtid' => $dest_mmtid]);
}
$failed = $total - count($ok);
$x += ['@total' => $total, '@ok' => count($ok), '@failed' => $failed];
if ($failed) {
if ($failed == $total) {
$this->messenger()->addStatus($this->t('You do not have permission to move any of the @total piece(s) of content on the @thing.', $x));
mm_set_form_redirect_to_mmtid($form_state, $src_mmtid);
}
else {
$this->messenger()->addStatus($this->t('Only @ok of the @total piece(s) of content on the @thing could be moved, due to lack of permission.', $x));
mm_set_form_redirect_to_mmtid($form_state, $dest_mmtid);
}
}
elseif (!$total) {
$this->messenger()->addStatus($this->t('There are no contents on this @thing to move.', $x));
mm_set_form_redirect_to_mmtid($form_state, $src_mmtid);
}
else {
$this->messenger()->addStatus($this->t('@total piece(s) of content were successfully moved.', $x));
mm_set_form_redirect_to_mmtid($form_state, $dest_mmtid);
}
}
}
private static function getValues($form_values, &$src_mmtid, &$modes, &$src_parent_mmtid, &$dest_mmtid) {
$src_mmtid = $form_values['mmtid'];
$copy_page = $form_values['mode'] == 'copy' && $form_values['copy_page'];
$modes = [
'copy_page' => $copy_page,
'copy_recur' => $copy_page && $form_values['copy_subpage'],
'copy_nodes' => $form_values['mode'] == 'copy' && $form_values['copy_nodes'],
'move_page' => $form_values['mode'] == 'move' && $form_values['move_mode'] == 'page',
'move_nodes' => $form_values['mode'] == 'move' && $form_values['move_mode'] == 'nodes',
];
$src_parent_mmtid = mm_content_get_parent($src_mmtid);
$dest_mmtid = mm_ui_mmlist_key0($form_values['dest']);
}
}
