monster_menus-9.0.x-dev/src/GetTreeIterator/SitemapDumpIter.php
src/GetTreeIterator/SitemapDumpIter.php
<?php
namespace Drupal\monster_menus\GetTreeIterator;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Database;
use Drupal\Core\File\FileExists;
use Drupal\monster_menus\Constants;
use Drupal\monster_menus\GetTreeIterator;
class SitemapDumpIter extends GetTreeIterator {
final public const FILE_PATH = 'public://sitemap.xml';
/**
* Database Service Object.
*
* @var Connection
*/
protected $database;
protected $fp, $tree_path, $max_level, $exclude, $in_home;
/**
* Constructs a SitemapDumpIter object.
*
* @param $max_level
* Maximum depth to dump
*/
public function __construct($max_level) {
$this->fp = fopen(self::FILE_PATH . '.temp', 'w');
if ($this->fp) {
$this->tree_path = [];
fwrite($this->fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n");
}
else {
\Drupal::logger('mm')->error('Could not create @path', ['@path' => self::FILE_PATH . '.temp']);
exit();
}
$this->max_level = $max_level;
$this->exclude = mm_get_setting('sitemap.exclude_list');
$this->database = Database::getConnection();
}
/**
* {@inheritdoc}
*/
public function iterate($item) {
// Root level.
if (!$item->level) {
return 1; // No error.
}
if ($item->level == 1) {
if ($item->mmtid == mm_home_mmtid()) {
$this->tree_path = [];
$this->in_home = 1;
}
else {
$this->in_home = 0;
}
}
// Not publicly readable, hidden, or recycled? Not the normal menu block?
if ($item->level > $this->max_level + $this->in_home || !$item->perms[Constants::MM_PERMS_READ] || $item->hidden || $item->perms[Constants::MM_PERMS_IS_RECYCLED] || !in_array($item->bid, [Constants::MM_MENU_UNSET, Constants::MM_MENU_DEFAULT, Constants::MM_MENU_BID]) ) {
return -1; // Skip children.
}
// Only traverse /users and the current site home.
if ($item->level == 1 && $item->mmtid != mm_content_users_mmtid() && $item->mmtid != mm_home_mmtid()) {
return -1; // Skip children.
}
if ($item->level >= 1 + $this->in_home) {
$node_name = empty($item->alias) ? $item->mmtid : $item->alias;
array_splice($this->tree_path, $item->level - 1 - $this->in_home);
$this->tree_path[] = $node_name;
}
$path = join('/', $this->tree_path);
// Check the exclusions list.
if (in_array($path, $this->exclude)) {
return -1; // Skip children.
}
// Figure out if the node or container is newer and use that date.
// Comment this out if it is too intensive (not required for the xml spec).
$select = $this->database->select('mm_tree', 't');
$select->leftJoin('mm_tree_revision', 'r', 'r.vid = t.vid');
$select->leftJoin('mm_node2tree', 'm', 't.mmtid = m.mmtid');
$select->leftJoin('node', 'n', 'm.nid = n.nid');
$select->condition('t.mmtid', $item->mmtid)
->groupBy('t.mmtid')
->groupBy('r.mtime');
$select->addField('r', 'mtime', 't_changed');
$select->addExpression('MAX(n.changed)', 'n_changed');
$mod_time = $select->execute()->fetchAssoc();
$max_mod_time = max($mod_time['t_changed'], $mod_time['n_changed']);
fwrite($this->fp, "<url>\n");
fwrite($this->fp, "\t<loc>" . htmlspecialchars(base_path() . $path, ENT_QUOTES) . "</loc>\n");
if (!is_null($max_mod_time)) {
fwrite($this->fp, "\t<lastmod>" . date('Y-m-d', $max_mod_time) . "</lastmod>\n");
}
// fwrite($this->fp, "\t<priority>".round(1/$item->level, 2)."</priority>\n");
fwrite($this->fp, "</url>\n");
return 1; // No error.
}
public function finish() {
fwrite($this->fp, "</urlset>\n");
fclose($this->fp);
$source = self::FILE_PATH . '.temp'; // Necessary for pass-by-reference.
\Drupal::service('file_system')->move($source, self::FILE_PATH, FileExists::Replace);
}
}