monster_menus-9.0.x-dev/src/Controller/MMTreeBrowserController.php
src/Controller/MMTreeBrowserController.php
<?php /** * @file * Contains \Drupal\monster_menus\Controller\MMTreeBrowserController. */ namespace Drupal\monster_menus\Controller; use Drupal\Component\Plugin\PluginManagerInterface; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Database\Connection; use Drupal\Core\Database\StatementInterface; use Drupal\Core\Extension\ModuleExtensionList; use Drupal\Core\Render\HtmlResponse; use Drupal\Core\Render\Markup; use Drupal\Core\Render\Renderer; use Drupal\Core\Render\RendererInterface; use Drupal\Core\Url; use Drupal\monster_menus\Constants; use Drupal\monster_menus\Entity\MMTree; use Drupal\monster_menus\MMTreeBrowserDisplay\MMTreeBrowserDisplayInterface; use Drupal\monster_menus\Plugin\MMTreeBrowserDisplay\Fallback; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Default controller for the monster_menus module. */ class MMTreeBrowserController extends ControllerBase { /** * The database connection. * * @var Connection */ protected $database; /** * The current page request. * * @var Request */ protected $request; /** * The renderer service. * * @var RendererInterface */ protected $renderer; /** * The plugin service. * * @var PluginManagerInterface */ protected $plugin_manager; /** * The display plugin. * * @var MMTreeBrowserDisplayInterface */ protected $plugin; /** * The module extension list service. * * @var ModuleExtensionList */ protected $module_extension_list; /** * MM Tree ID of the initially selected page. * * @var int */ protected $selected; /** * MM Tree ID of the topmost page shown in the tree. * * @var int */ protected $top_mmtid = 1; /** * Display mode constant. * * @var string */ protected $mode = Fallback::BROWSER_MODE_PAGE; /** * List of permissions a page can have in order to be visible. * * @var string */ protected $enabled = Constants::MM_PERMS_READ; /** * List of permissions a page can have in order to be selectable. * * @var string */ protected $selectable = ''; /** * Title to appear above the browser. * * @var string */ protected $title = ''; /** * The field name, bundle and type to display in the right hand pane. * * @var string */ protected $field_id; /** * List of allowed MIME types to display in the right hand pane. * * @var string */ protected $file_types; /** * Minimum width/height, in pixels, of images that are selectable by the user. * * @var string */ protected $min_wh; /** * Constructs a MMTreeBrowserController object. * * @param Connection $database * The database connection. * @param Request $request * The parameters of the current request. */ public function __construct(Connection $database, Request $request, Renderer $renderer, PluginManagerInterface $plugin_manager, ModuleExtensionList $extension_list_module) { $this->database = $database; $this->request = $request; $this->renderer = $renderer; $this->plugin_manager = $plugin_manager; $this->module_extension_list = $extension_list_module; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('database'), $container->get('request_stack')->getCurrentRequest(), $container->get('renderer'), $container->get('plugin.manager.mm_tree_browser_display'), $container->get('extension.list.module') ); } private function plugin($mode = '') { if (empty($this->plugin)) { $this->plugin = $this->plugin_manager->getInstance(['mode' => $mode ?: $this->request->query->getAlnum('browserMode')]); } return $this->plugin; } /** * Get a portion of the MM Tree as JSON. * * @param MMTree $mm_tree * Starting point * @return JsonResponse */ public function getTreeJson(MMTree $mm_tree) { if (($id = $this->request->query->getInt('_vusr', 1)) > 0) { $id = $mm_tree->id(); } return mm_json_response($this->getLeft($id), ['Pragma' => 'no-cache']); } /** * Get the render array for the outer tree structure. * * @return HtmlResponse */ public function getWrapperRenderable() { $path = explode('/', preg_replace('{//+}', '/', $this->request->query->get('_path'))); $start = array_shift($path); $params = explode('-', $start, 9); if (isset($path[0]) && $path[0] != $params[0]) { array_unshift($path, $params[0]); } elseif (!$path) { $path[] = 1; } $params = array_pad($params, 9, ''); $params = [ 'selected' => end($path), // MM Tree ID of the initially selected page. 'top_mmtid' => $path[0], // MM Tree ID of the topmost page shown in the tree. 'mode' => $params[1], // Display mode constant. 'enabled' => $params[3], // List of permissions a page can have in order to be visible. 'selectable' => $params[4], // List of permissions a page can have in order to be selectable. 'title' => $params[5], // Title to appear above the browser. 'field_id' => $params[6], // The field name, bundle, and type to display in the right hand pane. 'file_types' => $params[7], // List of allowed MIME types to display in the right hand pane. 'min_wh' => $params[8], // Minimum width/height, in pixels, of images that are selectable by the user. ]; foreach ($params as $name => $value) { $this->$name = $value; } return mm_page_wrapper( $this->t('Tree Browser'), $this->getWrapper(), ['id' => 'mm-media-assist-load', 'class' => ['mm-media-assist']] ); } /** * Get the right hand pane's contents as JSON. * * @return JsonResponse */ public function getRightJSON() { $get = $this->request->query->all(); if (empty($get['id']) || !($mmtid = intval(substr($get['id'], 5)))) { return mm_json_response([]); } $mode = $get['browserMode']; $actions = []; $dialogs = []; if (!$this->isBookmarked($mmtid, $mode)) { $actions['bkmark'] = [ '#type' => 'button', '#id' => mm_ui_modal_dialog([], $dialogs), '#value' => $this->t('Bookmark'), '#attributes' => [ 'title' => $this->t('Bookmark this location'), 'rel' => Url::fromRoute('monster_menus.browser_bookmark_add', ['mm_tree' => $mmtid], ['query' => array('browserMode' => $mode)] )->toString(), ] ]; } $item = mm_content_get($mmtid, Constants::MM_GET_FLAGS); $perms = $item->perms = mm_content_user_can($mmtid); $item->is_group = $perms[Constants::MM_PERMS_IS_GROUP]; $item->is_user = $perms[Constants::MM_PERMS_IS_USER]; $this->plugin()->alterRightButtons($mode, $this->request->query, $item, $perms, $actions, $dialogs); $actions['close'] = [ '#type' => 'button', '#value' => $this->t('Close window'), '#attributes' => ['rel' => '#close'], ]; mm_module_invoke_all_array('mm_browser_buttons_alter', [$mode, $item, &$actions, &$dialogs]); $content = $this->plugin()->viewRight($mode, $this->request->query, $perms, $item, $this->database); if ($content instanceof JsonResponse) { // View function returned JSON, so don't do any further processing. return $content; } if (is_array($content)) { $content = $this->renderer->renderRoot($content); } // Get the last viewed item $lastviewed = ''; if ($last_mmtid = $this->getLastViewed($mode)) { $lastviewed = $this->getRelativePath($last_mmtid, $get['browserTop']); } if (isset($get['id'])) { $this->setLastViewedMMTID(intval(substr($get['id'], 5))); } $actions = ['#type' => 'actions', 'actions' => $actions]; return mm_json_response([ 'title' => mm_content_get_name($item), 'links' => $this->renderer->renderRoot($actions), 'body' => $content, 'lastviewed' => $lastviewed, 'dialogs' => $dialogs['#attached']['drupalSettings']['MM']['MMDialog'] ?? [], ]); } /** * Determine whether or not a bookmark already exists. * * @return JsonResponse */ public function bookmarkExistsJSON() { return mm_json_response([ 'exists' => $this->isBookmarked($this->request->query->getInt('id'), $this->request->query->get('browserMode', '')) ]); } /** * Get all bookmarks as HTML. * * @return HtmlResponse */ public function getBookmarksHTML() { // Display bookmarks. $bookmarks = $this->getBookmarksRenderable($this->request->query->get('browserMode', ''), $this->top_mmtid); $resp = new HTMLResponse($this->renderer->renderRoot($bookmarks)); $resp->addCacheableDependency(CacheableMetadata::createFromRenderArray($bookmarks)); return $resp; } /** * Get the page last viewed by the user, if any, as JSON. * * @return null|JsonResponse */ public function getLastViewedJSON() { $query = $this->request->query; $return = NULL; if ($last_mmtid = $this->getLastViewed($query->get('browserMode', ''))) { $return = mm_json_response(['path' => $this->getRelativePath($last_mmtid, $query->get('browserTop'))]); } if ($get_id = $query->get('id', '')) { $this->setLastViewedMMTID(intval(substr($get_id, 0, 5))); } return $return; } /** * Set the last viewed page for the current user. * * @param MMTree $mm_tree */ public function setLastViewed(MMTree $mm_tree) { $this->setLastViewedMMTID($mm_tree->id()); } /** * Set the last viewed page for the current user. * * @param int $mmtid */ private function setLastViewedMMTID($mmtid) { $uid = $this->currentUser()->id(); $type = $this->plugin()->getBookmarksType($this->request->query->get('browserMode', '')) . '_last'; $this->database->merge('mm_tree_bookmarks') ->keys(array( 'uid' => $uid, 'type' => $type, 'weight' => 0, )) ->fields(['data' => $mmtid]) ->execute(); } /** * Get the UI form to add a bookmark, or submit the form to actually add the * bookmark. * * @param MMTree $mm_tree * MMTree entity of the page to be added. * @return Response * Response object. * @throws \Exception */ public function getAddBookmarkForm(MMTree $mm_tree) { $user_uid = $this->currentUser()->id(); $mmtid = $mm_tree->id(); $name = mm_content_get_name($mmtid); $mode = $this->request->query->get('browserMode', ''); if ($this->isBookmarked($mmtid, $mode)) { $output = [ '#theme' => 'mm_browser_bookmark_add', '#name' => '', '#mmtid' => '', ]; } elseif ($this->request->get('linktitle')) { $mm_bookmark_serialized = serialize([ 'title' => strip_tags($this->request->get('linktitle', '')), 'mmtid' => $mmtid, ]); $type = $this->plugin()->getBookmarksType($mode); $transaction = $this->database->startTransaction(); $select = $this->database->select('mm_tree_bookmarks', 'b') ->condition('b.uid', $user_uid) ->condition('b.type', $type); $select->addExpression('IFNULL(MAX(b.weight), -1) + 1', 'max_weight'); $max_weight = $select->execute()->fetchField(); $this->database->insert('mm_tree_bookmarks') ->fields([ 'uid' => $user_uid, 'weight' => $max_weight, 'type' => $type, 'data' => $mm_bookmark_serialized, ]) ->execute(); unset($transaction); return mm_json_response([]); } else { $output = [ '#theme' => 'mm_browser_bookmark_add', '#name' => $name, '#mmtid' => $mmtid, ]; } return new HtmlResponse((string) \Drupal::service('renderer')->renderRoot($output)); } /** * Get the bookmarks overview form. * * @return HtmlResponse */ public function getManageBookmarksForm() { $mode = $this->plugin()->getBookmarksType($this->request->query->get('browserMode', '')); $num_rows = $this->database->select('mm_tree_bookmarks', 'b') ->condition('b.uid', $this->currentUser()->id()) ->condition('b.type', $mode) ->countQuery()->execute()->fetchField(); $body = []; if ($num_rows < 1) { $body[] = ['#markup' => '<div id="message"><p>' . $this->t('No bookmarks found.') . '</p><p><input type="button" onclick="Drupal.mmDialogClose(); return false;" value="' . $this->t('Cancel') . '"></p></div>']; } else { $rows = []; $result = $this->getBookmarks($mode); while ($row = $result->fetchAssoc()) { $ds_data = unserialize($row['data']); $edit_js = "Drupal.mmBrowserEditBookmarkEdit(event)"; $rows['row_' . $ds_data['mmtid']] = [ 'item' => [ '#type' => 'item', '#markup' => '<div>' . htmlentities($ds_data['title']) . '</div>', '#wrapper_attributes' => ['name' => $ds_data['mmtid'], 'class' => ['tb-manage-name'], 'ondblclick' => $edit_js], ], 'delete' => mm_ui_js_link_no_href(['title' => $this->t('Remove this bookmark'), 'onclick' => "return Drupal.mmBrowserDeleteBookmarkConfirm(" . $ds_data['mmtid'] . ", this)"], $this->t('Delete')), 'edit' => mm_ui_js_link_no_href(['title' => $this->t('Edit this bookmark'), 'onclick' => 'return jQuery(this).closest("tr").find("td:first").dblclick()'], $this->t('Edit')), 'weight' => [ '#type' => 'weight', '#title' => $this->t('Weight for @title', ['@title' => $ds_data['mmtid']]), '#title_display' => 'invisible', '#delta' => 50, '#default_value' => count($rows), '#wrapper_attributes' => ['class' => ['menu-weight'], 'style' => ['display: none']], ], '#attributes' => ['class' => ['draggable', 'bookmark_tr_' . $ds_data['mmtid']]], ]; } $body[] = [ '#prefix' => '<div id="tb-manage-body"><form id="manage-bookmarks-form"><div id="manage-bookmarks-div">', '#type' => 'table', '#id' => 'manage-bookmarks-table', '#attributes' => ['class' => 'manage-bookmarks-table'], '#suffix' => '</div></form>', ] + $rows; } return new HtmlResponse((string) \Drupal::service('renderer')->renderRoot($body)); } private function getBookmarksCacheTag() { return 'user_bookmarks:' . $this->currentUser()->id(); } public function invalidateBookmarksCache() { Cache::invalidateTags([$this->getBookmarksCacheTag()]); } /** * Delete a bookmark. * * @param MMTree $mm_tree * Entity of the bookmarked page to delete. * @return JsonResponse * The deleted bookmark's ID. */ public function deleteBookmarkJSON(MMTree $mm_tree) { $mode = $this->request->query->get('browserMode', ''); $result = $this->getBookmarks($mode); $type = $this->plugin()->getBookmarksType($mode); while ($row = $result->fetchAssoc()) { $ds_data = unserialize($row['data']); if ($ds_data['mmtid'] == $mm_tree->id()) { $this->database->delete('mm_tree_bookmarks') ->condition('uid', $this->currentUser()->id()) ->condition('type', $type) ->condition('weight', $row['weight']) ->execute(); } } $this->invalidateBookmarksCache(); return mm_json_response(['mmtid' => $mm_tree->id()]); } /** * Change the title of a bookmark. * * @param MMTree $mm_tree * Entity of the bookmarked page to set the title for. * @return JsonResponse * The new title and the bookmark's ID. */ public function setBookmarkJSON(MMTree $mm_tree) { $title = strip_tags($this->request->get('title', '')); $mode = $this->request->query->get('browserMode', ''); $result = $this->getBookmarks($mode); $type = $this->plugin()->getBookmarksType($mode); while ($row = $result->fetchAssoc()) { $ds_data = unserialize($row['data']); if ($ds_data['mmtid'] == $mm_tree->id()) { $ds_data['title'] = $title; $ds_done = serialize($ds_data); $this->database->update('mm_tree_bookmarks') ->fields(['data' => $ds_done]) ->condition('uid', $this->currentUser()->id()) ->condition('type', $type) ->condition('weight', $row['weight']) ->execute(); } } $this->invalidateBookmarksCache(); return mm_json_response(['title' => $title, 'mmtid' => $mm_tree->id()]); } /** * Change the order of the list of bookmarks. * * @return JsonResponse * The new order. * @throws \Exception */ public function sortBookmarksJSON() { $neworder = explode('|', $this->request->get('neworder', '')); $mode = $this->request->query->get('browserMode', ''); $result = $this->getBookmarks($mode); $type = $this->plugin()->getBookmarksType($mode); $uid = $this->currentUser()->id(); $bookmarks = []; while ($row = $result->fetchAssoc()) { $ds_data = unserialize($row['data']); $bookmarks[$ds_data['mmtid']] = $ds_data; } $this->database->delete('mm_tree_bookmarks') ->condition('uid', $uid) ->condition('type', $type) ->execute(); $weight = 0; foreach ($neworder as $weight => $mmtid) { if (isset($bookmarks[$mmtid])) { $this->database->insert('mm_tree_bookmarks') ->fields([ 'weight' => $weight, 'uid' => $uid, 'type' => $type, 'data' => serialize($bookmarks[$mmtid]), ])->execute(); unset($bookmarks[$mmtid]); } } // Ensure any remaining bookmarks not in $neworder are preserved. foreach ($bookmarks as $mmtid => $ds_data) { $this->database->insert('mm_tree_bookmarks') ->fields([ 'weight' => $weight++, 'uid' => $uid, 'type' => $type, 'data' => serialize($ds_data)]) ->execute(); } $this->invalidateBookmarksCache(); return mm_json_response(['neworder' => $neworder]); } /** * Check to ensure a bookmark does not already exist prior to adding it. * * @param int $mmtid * MM Tree ID of the bookmark. * @param string $mode * Display mode constant. * @return bool */ private function isBookmarked($mmtid, $mode) { $already_exists = FALSE; $result = $this->getBookmarks($mode); foreach ($result as $row) { $ds_data = unserialize($row->data); if ($ds_data['mmtid'] == $mmtid) { $already_exists = TRUE; break; } } return $already_exists; } /** * Get the outer structure of the tree browser. * * @return array * Render array. */ private function getWrapper() { $this->plugin($this->mode); if (empty($this->title)) { $this->title = $this->plugin()->label($this->mode); } $this->title = strip_tags($this->title); if (!$this->top_mmtid) { $show_root = $this->top_mmtid === '0'; $this->top_mmtid = 1; } $out = []; $instance_id = $this->request->query->getInt('instanceId', 0); $settings = [ 'browserInstanceId' => $instance_id, 'libraryPath' => $this->module_extension_list->getPath('monster_menus') . '/libraries', 'browserDots' => $this->plugin()->showReservedEntries($this->mode), 'browserEnabled' => $this->enabled, 'browserMode' => $this->mode, 'browserSelectable' => $this->selectable, 'browserTop' => $this->top_mmtid, 'browserShowRoot' => (int) !empty($show_root), 'lastBrowserPath' => $this->getRelativePath($this->getLastViewed($this->mode), $this->top_mmtid), 'startBrowserPath' => $this->getRelativePath($this->selected, $this->top_mmtid), ]; if (!empty($this->field_id)) { $settings['browserFieldID'] = $this->field_id; } if (!empty($this->file_types)) { $settings['browserFileTypes'] = $this->file_types; } if (!empty($this->min_wh)) { $min_wh = explode('x', $this->min_wh); $settings += ['browserMinW' => $min_wh[0], 'browserMinH' => $min_wh[1]]; } mm_add_js_setting($out, 'mmBrowser', $settings); mm_ui_modal_dialog([], $out); mm_add_library($out, 'mm_browser'); mm_add_library($out, 'jsTree'); // Suppress the admin module \Drupal::moduleHandler()->invokeAll('suppress'); $out[] = [ '#prefix' => '<div id="mmtree-browse"><div id="mmtree-browse-nav">', $this->getURLs($this->mode, $this->top_mmtid), '#suffix' => <<<HTML <h2 class="mmtree-assist-title">$this->title</h2> </div> <div id="mmtree-browse-browser"> <div id="mmtree-browse-tree-wrapper"> <div id="mmtree-browse-tree"></div> </div> <div id="mmtree-browse-items"> <div id="mmtree-browse-header"> <h4 id="mmtree-assist-title"></h4> <div id="mmtree-assist-links"></div> </div> <div id="mmtree-assist-content"></div> </div> </div> </div> HTML ]; return $out; } /** * Create the list of URLs at the top of the tree browser. * * @param string $mode * Display mode constant. * @param int $top_mmtid * MM Tree ID of the topmost page shown in the tree. * @return array * Render array. */ private function getURLs($mode, $top_mmtid) { // Simple buttons come first. $urls = []; $allowed_top = $this->plugin()->getTreeTop($mode); if ($top_mmtid != $allowed_top) { $urls[] = ['#markup' => Markup::create('<button onclick="Drupal.mm_browser_goto_top(\'' . $allowed_top . '\');" class="button">' . $this->t('View entire tree') . '</button>')]; } $urls[] = ['#markup' => Markup::create('<button onclick="Drupal.mm_browser_last_viewed();" id="last-viewed-link" class="button">' . $this->t('Last location') . '</button>')]; foreach (mm_module_invoke_all('mm_browser_navigation', $mode, $top_mmtid) as $url) { $urls[] = is_array($url) ? $url : ['#markup' => Markup::create($url)]; } mm_module_invoke_all_array('mm_browser_menu_alter', [$mode, &$urls]); $arr = [ '#prefix' => '<div class="ui-widget bookmarks-list">', 'urls' => $urls, 'bookmarks' => $this->getBookmarksRenderable($mode, $top_mmtid), '#suffix' => '</div>', ]; mm_ui_modal_dialog('init', $arr); drupal_attach_tabledrag($arr, [ 'table_id' => 'manage-bookmarks-table', 'action' => 'order', 'relationship' => 'sibling', 'group' => 'menu-weight', ]); return $arr; } private function getBookmarksRenderable($mode, $top_mmtid) { $manage_url = Url::fromRoute('monster_menus.browser_bookmark_manage', [], ['query' => ['browserMode' => $mode]]); $bookmarks = [ 'dummy' => [ 'title' => Markup::create('<div>' . $this->t('Bookmarks') . '</div>'), 'url' => NULL, ], 'org' => [ 'title' => $this->t('Organize Bookmarks...'), 'url' => $manage_url, 'attributes' => ['class' => ['organize']], ] ]; $result = $this->getBookmarks($mode); while ($row = $result->fetchAssoc()) { $ds_data = unserialize($row['data']); $bookmarks[] = [ 'title' => $ds_data['title'], 'url' => Url::fromUserInput('#', ['fragment' => $this->getRelativePath($ds_data['mmtid'], $top_mmtid)]), ]; } return [ '#type' => 'dropbutton', '#links' => $bookmarks, '#cache' => ['contexts' => ['user'], 'tags' => [$this->getBookmarksCacheTag()]], '#attributes' => ['class' => ['mm-bookmarks']], ]; } /** * @param array $mmtid * 0 to get just the root, otherwise the MMTID to fetch the children of. * @return array * An array of entries, where any sub-entries are nested in 'children'. */ private function getLeft($mmtid) { $mm_children = array(); $get = $this->request->query->all(); $depth = !$mmtid ? 0 : 1; if ($mmtid == 0 || $mmtid == 1) { $mmtid = $this->plugin()->getTreeTop($get['browserMode']); } $params = array( Constants::MM_GET_TREE_ADD_TO_CACHE => TRUE, Constants::MM_GET_TREE_FILTER_BINS => FALSE, Constants::MM_GET_TREE_FILTER_DOTS => $get['browserDots'] == 'true', Constants::MM_GET_TREE_FILTER_HIDDEN => TRUE, Constants::MM_GET_TREE_DEPTH => $depth, Constants::MM_GET_TREE_RETURN_KID_COUNT => TRUE, Constants::MM_GET_TREE_RETURN_PERMS => TRUE, ); $this->plugin()->alterLeftQuery($get['browserMode'], $this->request->query, $params); $list = mm_content_get_tree($mmtid, $params); if ($depth) { array_shift($list); } foreach ($list as $item) { $class = []; $children = TRUE; $state = [ 'opened' => FALSE, 'disabled' => FALSE, 'selected' => FALSE ]; $attributes = []; $name = mm_content_get_name($item); $hidden = $item->state & Constants::MM_GET_TREE_STATE_HIDDEN; if ($hidden) { $name .= ' ' . t('(hidden)'); $class['mmtree-hidden'] = 1; } $text = $name; if (!empty($item->fid_list)) { // We can't get the count in SQL, so count the unique fids here. $fid_list = array_unique(explode(',', $item->fid_list)); $item->nodecount = count($fid_list); } if (isset($item->nodecount) && $item->nodecount > 0) { $text = t('@name <span class="mmtree-browse-filecount">@count</span>', array('@name' => $name, '@count' => $this->formatPlural($item->nodecount, '(1 item)', '(@count items)'))); } if ($item->state & Constants::MM_GET_TREE_STATE_LEAF) { $class['leaf'] = 1; $children = FALSE; } $denied = $item->state & Constants::MM_GET_TREE_STATE_DENIED || !empty($get['browserEnabled']) && !$item->perms[$get['browserEnabled']]; if ($denied) { $class['disabled'] = $class['leaf'] = 1; $state['disabled'] = TRUE; $children = FALSE; } $attributes['class'] = join(' ', array_keys($class)); $mm_children[] = array( 'id' => 'mmbr-' . $item->mmtid, 'text' => $text, 'state' => $state, 'children' => $children, 'a_attr' => $attributes, ); } return $mm_children; } /** * Get a path that is relative to the displayed tree's root. * * @param int $mmtid * MM Tree ID of the page in question. * @param int $top * MM Tree ID of the tree's root. * @return string * The relative path. */ private function getRelativePath($mmtid, $top) { $path = mm_content_get_full_path($mmtid); if (preg_match('{\b' . $top . '(/|$)(.*)}', $path, $matches)) { return $matches[0]; } return $path; } /** * Get the MMTID of the page last viewed by the current user. * * @param $mode * Display mode constant. * @return int|null * MM Tree ID of the last viewed page. */ private function getLastViewed($mode) { return $this->database->select('mm_tree_bookmarks', 'b') ->fields('b', array('data')) ->condition('b.uid', $this->currentUser()->id()) ->condition('b.type', $this->plugin()->getBookmarksType($mode) . '_last') ->execute()->fetchField(); } /** * Get a database object for the query containing the list of bookmarks for * the current user. * * @param $mode * Display mode constant. * @return StatementInterface * The database object. */ private function getBookmarks($mode) { return $this->database->select('mm_tree_bookmarks', 'b') ->fields('b') ->condition('b.uid', $this->currentUser()->id()) ->condition('b.type', $this->plugin()->getBookmarksType($mode)) ->orderBy('b.weight') ->execute(); } }