monster_menus-9.0.x-dev/src/GetTreeIterator/MMExportIter.php

src/GetTreeIterator/MMExportIter.php
<?php
namespace Drupal\monster_menus\GetTreeIterator;

use Drupal;
use Drupal\content_sync\ContentSyncManager;
use Drupal\content_sync\Exporter\ContentExporter;
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
use Drupal\monster_menus\Constants;
use Drupal\monster_menus\GetTreeIterator;
use Drupal\monster_menus\ImportExport;
use Drupal\monster_menus\MMCreatePath\MMCreatePathGroup;
use Drupal\monster_menus\MMCreatePath\MMCreatePathCat;
use Drupal\monster_menus\MMImportExportException;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\user\Entity\User;
use Symfony\Component\Yaml\Dumper;

class MMExportIter extends GetTreeIterator {

  /**
   * Database Service Object.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * Content sync service.
   *
   * @var ContentExporter
   */
  protected $contentExporter;

  /**
   * Content sync service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  public $nodes, $pages, $subrequest, $pool, $users, $parents, $aliases;
  private $include_nodes, $page_nodes, $dependencies;

  /**
   * Constructs an MMExportIter object.
   *
   * @param bool $include_nodes
   *   If TRUE, include node contents.
   */
  public function __construct($include_nodes) {
    $this->pages = $this->nodes = $this->parents = $this->aliases = $this->subrequest = $this->pool = $this->users = $this->page_nodes = $this->dependencies = [];
    $this->include_nodes = $include_nodes;
    $this->database = Database::getConnection();
    $this->entityTypeManager = Drupal::entityTypeManager();
    if ($include_nodes) {
      $this->contentExporter = \Drupal::service('content_sync.exporter');
    }
  }

  /**
   * {@inheritdoc}
   */
  public function iterate($item) {
    // Skip recycle bins
    if ($item->perms[Constants::MM_PERMS_IS_RECYCLE_BIN]) {
      return -1;
    }
    if (!$item->perms[Constants::MM_PERMS_READ]) {
      throw new MMImportExportException('You do not have permission to read the page/group with mmtid=@mmtid.', ['@mmtid' => $item->mmtid]);
    }
    // Create a new object and filter out unused fields.
    $compare = $item->perms[Constants::MM_PERMS_IS_GROUP] ? new MMCreatePathGroup([]) : new MMCreatePathCat([]);
    $i = (object)array_intersect_key((array)$item, (array)$compare);
    unset($i->mmtid);

    if (!empty($item->bid)) {
      $i->menu_start = $item->bid;
    }

    $i->perms = [];
    // Groups
    $select = $this->database->select('mm_tree', 't');
    $select->join('mm_tree_access', 'a', 'a.mmtid = t.mmtid');
    $select->leftJoin('mm_tree', 't2', 'a.gid = t2.mmtid');
    $result = $select->fields('t2', ['mmtid', 'name'])
      ->fields('a', ['mode'])
      ->condition('t2.mmtid', '0', '>=')
      ->condition('a.mmtid', $item->mmtid)
      ->execute();
    foreach ($result as $r) {
      if ($r->mmtid == $item->mmtid) {
        $i->perms[$r->mode]['groups'][] = 'self';
      }
      else {
        $i->perms[$r->mode]['groups'][$r->mmtid] = $this->addGroup($r->mmtid, $item->mmtid);
      }
    }

    // Individual users
    $select = $this->database->select('mm_tree', 't');
    $select->join('mm_tree_access', 'a', 'a.mmtid = t.mmtid');
    $result = $select->fields('a', ['mode', 'gid'])
      ->condition('a.gid', '0', '<')
      ->condition('a.mmtid', $item->mmtid)
      ->execute();
    foreach ($result as $r) {
      $i->perms[$r->mode]['users'] = [];
      foreach (mm_content_get_uids_in_group($r->gid) as $uid) {
        $i->perms[$r->mode]['users'][] = $this->uid2username($uid);
      }
    }

    // Owner
    $i->uid = $this->uid2username($i->uid);

    if ($item->perms[Constants::MM_PERMS_IS_GROUP]) {
      if ($i->vgroup = mm_content_is_vgroup($item->mmtid)) {
        // Virtual group
        $vquery = $this->database->query('SELECT qfrom, field FROM {mm_group} g INNER JOIN {mm_vgroup_query} v ON g.vgid = v.vgid WHERE g.gid = :mmtid', [':mmtid' => $item->mmtid])->fetchObject();
        if ($vquery) {
          $i->qfrom = $vquery->qfrom;
          $i->qfield = $vquery->field;
        }
      }
      else {
        // Regular group
        $i->members = [];
        foreach (mm_content_get_uids_in_group($item->mmtid) as $uid) {
          $i->members[] = $this->uid2username($uid);
        }
      }
    }
    else {
      // Cascaded settings
      $result = $this->database->query('SELECT * FROM {mm_cascaded_settings} WHERE mmtid = :mmtid', [':mmtid' => $item->mmtid]);
      foreach ($result as $r) {
        if ($r->multiple) {
          if (!isset($i->cascaded) || empty($i->cascaded[$r->name])) {
            $i->cascaded[$r->name] = [];
          }
          $i->cascaded[$r->name][] = $r->data;
        }
        else {
          $i->cascaded[$r->name] = $r->data;
        }
      }

      // Nodes
      if ($this->include_nodes) {
        if ($nids = mm_content_get_nids_by_mmtid($item->mmtid)) {
          foreach (array_diff($nids, array_keys($this->nodes)) as $new_nid) {
            $this->nodes[$new_nid] = TRUE;
          }
          // Convert string nids to integers, to help shorten output.
          $this->page_nodes[$item->mmtid] = array_map(fn($nid) => (int) $nid, $nids);
        }
      }
    }

    $this->pool[$item->mmtid] = $item->perms[Constants::MM_PERMS_IS_GROUP] ? new MMCreatePathGroup((array) $i) : new MMCreatePathCat((array) $i);
    if (!$this->subrequest) {
      array_splice($this->aliases, $item->level);
      $this->aliases[] = $item->alias;
      array_splice($this->parents, $item->level);
      $this->parents[] = (int) $item->mmtid;
      $this->pages[join('/', $this->aliases)] = $this->parents;
    }

    return 1;
  }

  public function dump() {
    $out = 'version: ' . ImportExport::MM_IMPORT_VERSION . "\n\n";
    if ($this->nodes) {
      $out .= "nodes:\n";
      $serializer_context = ['content_sync_file_base_64' => TRUE];
      $language = \Drupal::languageManager()->getCurrentLanguage()->getId();
      foreach (array_keys($this->nodes) as $nid) {
        /** @var NodeInterface $node */
        if ($node = Node::load($nid)) {
          unset($node->mm_catlist);

          if ($node->__get('users_w')) {
            $new_users = [];
            foreach (array_keys($node->__get('users_w')) as $uid) {
              $new_users[$this->uid2username($uid)] = '';
            }
            $node->__set('users_w', $new_users);
          }

          if ($node->__get('groups_w')) {
            $groups_w = [];
            foreach (array_keys($node->__get('groups_w')) as $gid) {
              $groups_w[$gid] = $this->addGroup($gid);
            }
            $node->__set('groups_w', $groups_w);
          }

          $node = $node->getTranslation($language);
          $exported_node_yaml = trim($this->contentExporter->exportEntity($node, $serializer_context));
          $exported_node_yaml = $this->addDependencies($exported_node_yaml, $serializer_context);
          $out .= "  $nid:\n    " . str_replace("\n", "\n    ", $exported_node_yaml) . "\n";
        }
      }
      $out .= "page_nodes:\n";
      foreach ($this->pool as $mmtid => $item) {
        if (isset($this->page_nodes[$mmtid])) {
          $out .= "  $mmtid:\n" . $this->exportVar($this->page_nodes[$mmtid], '    ');
        }
      }
      if ($this->dependencies) {
        $out .= "\ndependencies:\n" . join('', $this->dependencies);
      }
    }
    else {
      $out .= "nodes: {}\n\npage_nodes: {}\n";
    }
    $out .= "pages:\n";
    $out .= $this->exportVar($this->pages, '  ');
    $out .= "\npool:\n";
    foreach ($this->pool as $mmtid => $item) {
      $out .= "  $mmtid:\n" . $this->exportVar($item, '    ');
    }
    return $out;
  }

  private function addDependencies($exported_yaml, $serializer_context) {
    $exported_entity = Yaml::decode($exported_yaml);

    if (isset($exported_entity['_content_sync']['entity_dependencies'])) {
      foreach ($exported_entity['_content_sync']['entity_dependencies'] as $type => $depends) {
        if (!in_array($type, ['user', 'node', 'mm_tree'])) {
          foreach ($depends as $depend) {
            if (!isset($this->dependencies[$depend])) {
              [$type, , $uuid] = explode(ContentSyncManager::DELIMITER, $depend);
              if ($entities = $this->entityTypeManager->getStorage($type)->loadByProperties(['uuid' => $uuid])) {
                // Prevent the recursive call to this function from exporting
                // the dependency again.
                $this->dependencies[$depend] = TRUE;
                $exported_yaml = trim($this->contentExporter->exportEntity(reset($entities), $serializer_context));
                $exported_yaml = $this->addDependencies($exported_yaml, $serializer_context);
                $this->dependencies[$depend] = "  $depend:\n    " . str_replace("\n", "\n    ", $exported_yaml) . "\n";
              }
            }
          }
        }
      }
    }

    // Look for references content_sync has missed.
    $walk = function (&$elem, &$content_sync) use (&$walk, $serializer_context) {
      if (is_array($elem)) {
        if (isset($elem['target_type']) && $elem['target_type'] != 'user' && $elem['target_type'] != 'node' && isset($elem['target_uuid'])) {
          if ($entities = $this->entityTypeManager->getStorage($elem['target_type'])->loadByProperties(['uuid' => $elem['target_uuid']])) {
            $entity = reset($entities);
            if ($elem['target_type'] == 'mm_tree') {
              unset($elem['target_type']);
              unset($elem['target_uuid']);
              $elem['target_id'] = $entity->id();
            }
            else {
              $depend = implode(ContentSyncManager::DELIMITER, [$entity->getEntityTypeId(), $entity->bundle(), $entity->uuid()]);
              if (!isset($this->dependencies[$depend])) {
                // Prevent the recursive call to this function from exporting the
                // dependency again.
                $this->dependencies[$depend] = TRUE;
                $exported_yaml = trim($this->contentExporter->exportEntity($entity, $serializer_context));
                $exported_yaml = $this->addDependencies($exported_yaml, $serializer_context);
                $this->dependencies[$depend] = "  $depend:\n    " . str_replace("\n", "\n    ", $exported_yaml) . "\n";
                $content_sync[$entity->getEntityTypeId()][] = $depend;
              }
            }
          }
        }
        else {
          foreach ($elem as &$e) {
            $walk($e, $content_sync);
          }
        }
      }
    };
    $walk($exported_entity, $exported_entity['_content_sync']['entity_dependencies']);

    unset($exported_entity['_content_sync']['entity_dependencies']['user']);
    unset($exported_entity['_content_sync']['entity_dependencies']['mm_tree']);
    return Yaml::encode($exported_entity);
  }

  /**
   * Export a field to YAML.
   */
  private function exportVar($var, $prefix = '') {
    $var = (array) $var;
    $dumper = new Dumper(2);
    return $dumper->dump($var, 100, strlen($prefix));
//    return $prefix . str_replace("\n", "\n$prefix", Yaml::encode($var));
  }

  private function uid2username($uid) {
    if (!isset($this->users[$uid])) {
      $loaded = User::load($uid);
      if (!$loaded) {
        throw new MMImportExportException('Unknown user with uid=@uid.', ['@uid' => $uid]);
      }
      $this->users[$uid] = $loaded->getAccountName();
    }
    return $this->users[$uid];
  }

  private function addGroup($gid, $orig_mmtid = NULL) {
    $groups_mmtid = mm_content_groups_mmtid();
    $out = [];
    foreach (mm_content_get_parents_with_self($gid) as $mmtid) {
      if ($mmtid != 1 && $mmtid != $groups_mmtid) {
        if (!isset($this->pool[$mmtid])) {
          if ($orig_mmtid && in_array($mmtid, $this->subrequest)) {
            throw new MMImportExportException('The groups with mmtid=@mmtid1 and mmtid=@mmtid2 have a circular reference which cannot be exported.', ['@mmtid1' => $orig_mmtid, '@mmtid2' => $mmtid]);
          }
          $temp_item = mm_content_get($mmtid, [Constants::MM_GET_FLAGS]);
          $temp_item->perms = mm_content_user_can($mmtid);
          $this->subrequest[] = $mmtid;
          $this->iterate($temp_item);
          array_pop($this->subrequest);
        }
        $out[] = (int) $mmtid;
      }
    }
    return $out;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc