monster_menus-9.0.x-dev/src/GetTreeIterator/ContentCopyIter.php
src/GetTreeIterator/ContentCopyIter.php
<?php
namespace Drupal\monster_menus\GetTreeIterator;
use Drupal\comment\Entity\Comment;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Database;
use Drupal\monster_menus\Constants;
use Drupal\monster_menus\GetTreeIterator;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
class ContentCopyIter extends GetTreeIterator {
/**
* The database connection.
*
* @var Connection
*/
protected $database;
public $first_mmtid, $dest_mmtid, $error, $cont_userlist, $cont_grouplist, $nodemap, $options, $predefined_flags;
/**
* Constructs a ContentCopyIter object.
*
* @param int $src_mmtid
* MMTID of copy source
* @param int $dest_mmtid
* MMTID of copy destination
* @param array $options
* Options for copy operation
*/
public function __construct($src_mmtid, $dest_mmtid, array $options) {
$defaults = [
Constants::MM_COPY_ALIAS => NULL,
Constants::MM_COPY_COMMENTS => FALSE,
Constants::MM_COPY_CONTENTS => FALSE,
Constants::MM_COPY_ITERATE_ALTER => NULL,
Constants::MM_COPY_NAME => NULL,
Constants::MM_COPY_NODE_PRESAVE_ALTER => NULL,
Constants::MM_COPY_OWNER => NULL,
Constants::MM_COPY_READABLE => FALSE,
Constants::MM_COPY_RECUR => TRUE,
Constants::MM_COPY_TREE => TRUE,
Constants::MM_COPY_TREE_PRESAVE_ALTER => NULL,
Constants::MM_COPY_TREE_SKIP_DUPS => FALSE,
];
$this->options = array_merge($defaults, $options);
$this->dest_mmtid = $dest_mmtid;
$this->nodemap = [mm_content_get_parent($src_mmtid) => $dest_mmtid];
$hooks = [
Constants::MM_COPY_ITERATE_ALTER => 'mm_copy_tree_iterate_alter',
Constants::MM_COPY_TREE_PRESAVE_ALTER => 'mm_copy_tree_tree_alter',
Constants::MM_COPY_NODE_PRESAVE_ALTER => 'mm_copy_tree_node_alter',
];
foreach ($hooks as $constant => $hook) {
$this->options[$constant] = isset($this->options[$constant]) ? (array) $this->options[$constant] : [];
$this->options[$constant] += mm_module_implements($hook);
}
if ($this->options[Constants::MM_COPY_CONTENTS] && !$this->options[Constants::MM_COPY_TREE]) {
mm_content_get_default_node_perms($dest_mmtid, $this->cont_grouplist, $this->cont_userlist, 0);
}
$this->predefined_flags = \Drupal::moduleHandler()->invokeAll('mm_tree_flags');
$this->database = Database::getConnection();
}
/**
* {@inheritdoc}
*/
public function iterate($item) {
if (isset($this->error)) {
// was set in a previous invocation
return 0;
}
if ($this->options[Constants::MM_COPY_READABLE] && !$item->perms[Constants::MM_PERMS_READ]) {
// skip this node and kids
return -1;
}
if ($item->name == Constants::MM_ENTRY_NAME_RECYCLE) {
// recycle bin: skip this node and kids
return -1;
}
$options_temp = $this->options;
if (is_array($options_temp[Constants::MM_COPY_ITERATE_ALTER])) {
foreach ($options_temp[Constants::MM_COPY_ITERATE_ALTER] as $alter) {
switch (call_user_func_array($alter, [&$item, &$options_temp])) {
case 1: // skip this one
return 1;
case -1: // skip this one and kids
return -1;
case 0: // completely stop
return 0;
}
}
}
if ($options_temp[Constants::MM_COPY_CONTENTS] && !$options_temp[Constants::MM_COPY_TREE]) {
if (!isset($this->first_mmtid)) {
$this->nodemap[$item->mmtid] = $this->dest_mmtid;
}
else {
$exists = mm_content_get(['parent' => $this->nodemap[$item->parent], 'alias' => $item->alias]);
if ($exists) {
$this->nodemap[$item->mmtid] = $exists[0]->mmtid;
}
else {
$this->error = t('There is no destination page with the URL alias %alias to copy the content to.', ['%alias' => $item->alias]);
return 0;
}
}
}
else {
$dest_mmtid = $this->nodemap[$item->parent];
$alias = is_null($options_temp[Constants::MM_COPY_ALIAS]) ? $item->alias : $options_temp[Constants::MM_COPY_ALIAS];
$exists = FALSE;
if ($options_temp[Constants::MM_COPY_TREE_SKIP_DUPS] && !empty($alias)) {
$tree = mm_content_get(['parent' => $dest_mmtid, 'alias' => $alias]);
if ($tree) {
$this->nodemap[$item->mmtid] = $tree[0]->mmtid;
$exists = TRUE;
}
}
if (!$exists) {
$perms = [];
$select = $this->database->select('mm_tree', 't');
$select->join('mm_tree_access', 'a', 't.mmtid = a.gid');
$select->fields('t', ['mmtid'])
->fields('a', ['mode'])
->condition('a.gid', 0, '>=')
->condition('a.mmtid', $item->mmtid);
$result = $select->execute();
foreach ($result as $r) {
$perms[$r->mode]['groups'][] = $r->mmtid;
}
$select = $this->database->select('mm_tree_access', 'a');
$select->join('mm_group', 'g', 'g.gid = a.gid');
$select->fields('a', ['mode'])
->fields('g', ['uid'])
->condition('a.gid', 0, '<')
->condition('a.mmtid', $item->mmtid);
$result = $select->execute();
foreach ($result as $r) {
$perms[$r->mode]['users'][] = $r->uid;
}
$result = $this->database->select('mm_tree_block', 'b')
->fields('b', ['bid', 'max_depth', 'max_parents'])
->condition('b.mmtid', $item->mmtid)
->execute();
if ($item->is_group || !($block = $result->fetchAssoc())) {
$block = ['bid' => Constants::MM_MENU_DEFAULT, 'max_depth' => -1, 'max_parents' => -1];
}
if (!isset($this->nodemap[$item->parent])) {
$this->error = t('Unexpected tree structure');
return 0;
}
$new = [
'name' => !empty($options_temp[Constants::MM_COPY_NAME]) ? $options_temp[Constants::MM_COPY_NAME] : $item->name,
'alias' => $alias,
'default_mode' => $item->default_mode,
'uid' => $options_temp[Constants::MM_COPY_OWNER] ?? $item->uid,
'cascaded' => mm_content_get_cascaded_settings($item->mmtid),
'perms' => $perms,
'menu_start' => $block['bid'],
'max_depth' => $block['max_depth'],
'max_parents' => $block['max_parents'],
];
foreach (['theme', 'flags', 'rss', 'node_info', 'previews', 'hidden', 'comment'] as $field) {
$new[$field] = $item->$field;
}
if (isset($this->first_mmtid)) {
$new['weight'] = $item->weight;
}
foreach ($this->predefined_flags as $flag => $elem) {
if (isset($elem['#flag_copy']) && $elem['#flag_copy'] === FALSE) {
unset($new['flags'][$flag]);
}
}
if (is_array($options_temp[Constants::MM_COPY_TREE_PRESAVE_ALTER])) {
foreach ($options_temp[Constants::MM_COPY_TREE_PRESAVE_ALTER] as $alter) {
call_user_func_array($alter, [&$new, $dest_mmtid]);
}
}
$this->nodemap[$item->mmtid] = mm_content_insert_or_update(TRUE, $dest_mmtid, $new);
}
} // $options_temp[MM_COPY_CONTENTS] && !$options_temp[MM_COPY_TREE]
if (!isset($this->first_mmtid)) {
$this->first_mmtid = $this->nodemap[$item->mmtid];
$this->options[Constants::MM_COPY_NAME] = $this->options[Constants::MM_COPY_ALIAS] = NULL;
}
if ($options_temp[Constants::MM_COPY_CONTENTS]) {
/** @var NodeInterface $node */
foreach (Node::loadMultiple(mm_content_get_nids_by_mmtid($item->mmtid)) as $nid => $node) {
if (!empty($nid)) {
$copy = $node->createDuplicate();
$copy->__set('mm_catlist', [$this->nodemap[$item->mmtid] => '']);
$copy->__set('mm_catlist_restricted', []);
$copy->setCreatedTime(mm_request_time());
unset($copy->recycle_date);
unset($copy->recycle_bins);
unset($copy->recycle_from_mmtids);
if ($options_temp[Constants::MM_COPY_CONTENTS] && !$options_temp[Constants::MM_COPY_TREE] && !$copy->__get('others_w')) {
$copy->__set('groups_w', $this->cont_grouplist);
$copy->__set('users_w', $this->cont_userlist);
}
if (is_array($options_temp[Constants::MM_COPY_NODE_PRESAVE_ALTER])) {
foreach ($options_temp[Constants::MM_COPY_NODE_PRESAVE_ALTER] as $alter) {
// Yes, $node->mm_catlist is intentional here, since we want the
// list from the source node.
call_user_func_array($alter, [&$copy, $node->__get('mm_catlist')]);
}
}
if (empty($copy->label())) {
// Title must be non-empty for save() to succeed.
$copy->setTitle(t('[untitled]'));
}
$copy->save();
if (($copy_nid = $copy->id()) && $options_temp[Constants::MM_COPY_COMMENTS] && mm_module_exists('comment')) {
$comment_map = [];
$comment_entity_manager = \Drupal::entityTypeManager()->getStorage('comment');
// Yes, $nid is intentional here, since we want the ID of the source
// node.
$result = \Drupal::service('entity.query')
->get('comment')
->condition('entity_id', $nid)
->execute();
/** @var Comment $comment */
foreach ($comment_entity_manager->loadMultiple($result) as $old_cid => $comment) {
$cloned = $comment->createDuplicate();
$cloned->set('entity_id', $copy_nid)
->save();
$comment_map[$old_cid] = $cloned->id();
}
foreach ($comment_map as $old_cid => $new_cid) {
$result = \Drupal::service('entity.query')
->get('comment')
->condition('pid', $old_cid)
->condition('entity_id', $copy_nid)
->execute();
foreach ($comment_entity_manager->loadMultiple($result) as $comment) {
$comment->set('pid', $new_cid)
->save();
\Drupal::service('comment.statistics')->update($comment);
}
}
}
\Drupal::logger('mm')->notice('%type: During copy, copied node nid=@id1 (%name) to nid=@id2',
['%type' => $copy->getType(), '%name' => $copy->label(), '@id1' => $nid, '@id2' => $copy_nid]);
}
}
}
if ($item->is_group) { // copy group entries
$select = $this->database->select('mm_group', 'g');
$select->addExpression(':gid', 'gid', [':gid' => $this->nodemap[$item->mmtid]]);
$select->addField('g', 'uid');
$select->condition('g.gid', $item->mmtid);
$this->database->insert('mm_group')
->from($select)
->execute();
}
return 1;
}
public function output() {
return $this->error ?? $this->first_mmtid;
}
}
