/** * {@inheritdoc} */ public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match) { $json = []; $json['content'] = (string) $this->renderer->renderRoot($main_content); if (!empty($main_content['#title'])) { $json['title'] = (string) $main_content['#title']; } else { $json['title'] = (string) $this->titleResolver->getTitle($request, $route_match->getRouteObject()); } $response = new CacheableJsonResponse($json, 200); $response->addCacheableDependency(CacheableMetadata::createFromRenderArray($main_content)); return $response; }
/** * Converts a render array into an HtmlFragment object. * * @param array|\Drupal\Core\Page\HtmlFragmentInterface|\Symfony\Component\HttpFoundation\Response $page_content * The page content area to display. * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * * @return \Drupal\Core\Page\HtmlPage * A page object. * * @throws \InvalidArgumentException * Thrown if the controller returns a string. */ protected function createHtmlFragment($page_content, Request $request) { // Allow controllers to return a HtmlFragment or a Response object directly. if ($page_content instanceof HtmlFragment || $page_content instanceof Response) { return $page_content; } if (is_string($page_content)) { throw new \InvalidArgumentException('_content controllers are not allowed to return strings. You can return a render array, a html fragment or a response object.'); } $fragment = $this->renderHtmlRenderer->render($page_content); if (!$fragment->getTitle() && ($route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT))) { $fragment->setTitle($this->titleResolver->getTitle($request, $route), Title::PASS_THROUGH); } return $fragment; }
/** * Converts a render array into an HtmlFragment object. * * @param array|string $page_content * The page content area to display. * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * * @return \Drupal\Core\Page\HtmlPage * A page object. */ protected function createHtmlFragment($page_content, Request $request) { // Allow controllers to return a HtmlFragment or a Response object directly. if ($page_content instanceof HtmlFragment || $page_content instanceof Response) { return $page_content; } if (!is_array($page_content)) { $page_content = ['#markup' => $page_content]; } $fragment = $this->renderHtmlRenderer->render($page_content); if (!$fragment->getTitle() && ($route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT))) { $fragment->setTitle($this->titleResolver->getTitle($request, $route), Title::PASS_THROUGH); } return $fragment; }
/** * Processes a successful controller into an HTTP 200 response. * * Some controllers may not return a response object but simply the body of * one. The VIEW event is called in that case, to allow us to mutate that * body into a Response object. In particular we assume that the return * from an JSON-type response is a JSON string, so just wrap it into a * Response object. * * @param Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event * The Event to process. */ public function onView(GetResponseForControllerResultEvent $event) { $request = $event->getRequest(); // For a master request, we process the result and wrap it as needed. // For a subrequest, all we want is the string value. We assume that // is just an HTML string from a controller, so wrap that into a response // object. The subrequest's response will get dissected and placed into // the larger page as needed. if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { $method = 'on' . $this->negotiation->getContentType($request); if (method_exists($this, $method)) { $event->setResponse($this->{$method}($event)); } else { $event->setResponse(new Response('Not Acceptable', 406)); } } else { // This is a new-style Symfony-esque subrequest, which means we assume // the body is not supposed to be a complete page but just a page // fragment. $page_result = $event->getControllerResult(); if ($page_result instanceof HtmlPage || $page_result instanceof Response) { return $page_result; } if (!is_array($page_result)) { $page_result = array('#markup' => $page_result); } // If no title was returned fall back to one defined in the route. if (!isset($page_result['#title'])) { $page_result['#title'] = $this->titleResolver->getTitle($request, $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)); } $event->setResponse(new Response(drupal_render_root($page_result))); } }
/** * Prepares the HTML body: wraps the main content in #type 'page'. * * @param array $main_content * The render array representing the main content. * @param \Symfony\Component\HttpFoundation\Request $request * The request object, for context. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match, for context. * * @return array * An array with two values: * 0. A #type 'page' render array. * 1. The page title. * * @throws \LogicException * If the selected display variant does not implement PageVariantInterface. */ protected function prepare(array $main_content, Request $request, RouteMatchInterface $route_match) { // If the _controller result already is #type => page, // we have no work to do: The "main content" already is an entire "page" // (see html.html.twig). if (isset($main_content['#type']) && $main_content['#type'] === 'page') { $page = $main_content; } else { // Select the page display variant to be used to render this main content, // default to the built-in "simple page". $event = new PageDisplayVariantSelectionEvent('simple_page', $route_match); $this->eventDispatcher->dispatch(RenderEvents::SELECT_PAGE_DISPLAY_VARIANT, $event); $variant_id = $event->getPluginId(); // We must render the main content now already, because it might provide a // title. We set its $is_root_call parameter to FALSE, to ensure // placeholders are not yet replaced. This is essentially "pre-rendering" // the main content, the "full rendering" will happen in // ::renderResponse(). // @todo Remove this once https://www.drupal.org/node/2359901 lands. if (!empty($main_content)) { $this->renderer->executeInRenderContext(new RenderContext(), function () use(&$main_content) { if (isset($main_content['#cache']['keys'])) { // Retain #title, otherwise, dynamically generated titles would be // missing for controllers whose entire returned render array is // render cached. $main_content['#cache_properties'][] = '#title'; } return $this->renderer->render($main_content, FALSE); }); $main_content = $this->renderCache->getCacheableRenderArray($main_content) + ['#title' => isset($main_content['#title']) ? $main_content['#title'] : NULL]; } // Instantiate the page display, and give it the main content. $page_display = $this->displayVariantManager->createInstance($variant_id); if (!$page_display instanceof PageVariantInterface) { throw new \LogicException('Cannot render the main content for this page because the provided display variant does not implement PageVariantInterface.'); } $page_display->setMainContent($main_content)->setConfiguration($event->getPluginConfiguration()); // Generate a #type => page render array using the page display variant, // the page display will build the content for the various page regions. $page = array('#type' => 'page'); $page += $page_display->build(); } // $page is now fully built. Find all non-empty page regions, and add a // theme wrapper function that allows them to be consistently themed. $regions = \Drupal::theme()->getActiveTheme()->getRegions(); foreach ($regions as $region) { if (!empty($page[$region])) { $page[$region]['#theme_wrappers'][] = 'region'; $page[$region]['#region'] = $region; } } // Allow hooks to add attachments to $page['#attached']. $this->invokePageAttachmentHooks($page); // Determine the title: use the title provided by the main content if any, // otherwise get it from the routing information. $title = isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver->getTitle($request, $route_match->getRouteObject()); return [$page, $title]; }
/** * {@inheritdoc} */ public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match) { $response = new AjaxResponse(); // First render the main content, because it might provide a title. $content = drupal_render_root($main_content); // Attach the library necessary for using the OpenDialogCommand and set the // attachments for this Ajax response. $main_content['#attached']['library'][] = 'core/drupal.dialog.ajax'; $response->setAttachments($main_content['#attached']); // Determine the title: use the title provided by the main content if any, // otherwise get it from the routing information. $title = isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver->getTitle($request, $route_match->getRouteObject()); // Determine the dialog options and the target for the OpenDialogCommand. $options = $request->request->get('dialogOptions', array()); $target = $this->determineTargetSelector($options, $route_match); $response->addCommand(new OpenDialogCommand($target, $title, $content, $options)); return $response; }
/** * {@inheritdoc} */ public function blockContents() { $sharethis_config = $this->configFactory->get('sharethis.settings'); $config = $this->configFactory->get('system.site'); if ($sharethis_config->get('location') == 'block') { // First Get all of the options for sharethis widget from database. $data_options = $this->getOptions(); $current_path = \Drupal::routeMatch()->getRouteName() ? Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath() : ''; $path = isset($current_path) ? $current_path : '<front>'; global $base_url; $path_obj = Url::fromUri($base_url . '/' . $path, array('absolute' => TRUE)); $m_path = $path_obj->toString(); $request = \Drupal::request(); $route_match = \Drupal::routeMatch(); $mtitle = $this->titleResolver->getTitle($request, $route_match->getRouteObject()); $m_title = is_object($mtitle) ? $mtitle->getUntranslatedString() : $config->get('name'); return $this->renderSpans($data_options, $m_title, $m_path); } }
/** * {@inheritdoc} */ public function render(array $output, $status_code = 200) { if (!isset($output['#title'])) { $output['#title'] = $this->titleResolver->getTitle(\Drupal::request(), \Drupal::routeMatch()->getRouteObject()); } $page = new HtmlPage('', isset($output['#cache']) ? $output['#cache'] : array(), $output['#title']); $page_array = drupal_prepare_page($output); $page = $this->fragmentRenderer->preparePage($page, $page_array); $page->setBodyTop(drupal_render($page_array['page_top'])); $page->setBodyBottom(drupal_render($page_array['page_bottom'])); $page->setContent(drupal_render($page_array)); $page->setStatusCode($status_code); return $page; }
/** * {@inheritdoc} */ public function build(RouteMatchInterface $route_match) { $breadcrumb = new Breadcrumb(); $links = array(); // General path-based breadcrumbs. Use the actual request path, prior to // resolving path aliases, so the breadcrumb can be defined by simply // creating a hierarchy of path aliases. $path = trim($this->context->getPathInfo(), '/'); $path_elements = explode('/', $path); $exclude = array(); // Don't show a link to the front-page path. $front = $this->config->get('page.front'); $exclude[$front] = TRUE; // /user is just a redirect, so skip it. // @todo Find a better way to deal with /user. $exclude['/user'] = TRUE; // Because this breadcrumb builder is entirely path-based, vary by the // 'url.path' cache context. $breadcrumb->addCacheContexts(['url.path']); while (count($path_elements) > 1) { array_pop($path_elements); // Copy the path elements for up-casting. $route_request = $this->getRequestForPath('/' . implode('/', $path_elements), $exclude); if ($route_request) { $route_match = RouteMatch::createFromRequest($route_request); $access = $this->accessManager->check($route_match, $this->currentUser, NULL, TRUE); // The set of breadcrumb links depends on the access result, so merge // the access result's cacheability metadata. $breadcrumb = $breadcrumb->addCacheableDependency($access); if ($access->isAllowed()) { $title = $this->titleResolver->getTitle($route_request, $route_match->getRouteObject()); if (!isset($title)) { // Fallback to using the raw path component as the title if the // route is missing a _title or _title_callback attribute. $title = str_replace(array('-', '_'), ' ', Unicode::ucfirst(end($path_elements))); } $url = Url::fromRouteMatch($route_match); $links[] = new Link($title, $url); } } } if ($path && '/' . $path != $front) { // Add the Home link, except for the front page. $links[] = Link::createFromRoute($this->t('Home'), '<front>'); } return $breadcrumb->setLinks(array_reverse($links)); }
/** * {@inheritdoc} */ public function build(RouteMatchInterface $route_match) { $links = array(); // General path-based breadcrumbs. Use the actual request path, prior to // resolving path aliases, so the breadcrumb can be defined by simply // creating a hierarchy of path aliases. $path = trim($this->context->getPathInfo(), '/'); $path_elements = explode('/', $path); $exclude = array(); // Don't show a link to the front-page path. $front = $this->config->get('page.front'); $exclude[$front] = TRUE; // /user is just a redirect, so skip it. // @todo Find a better way to deal with /user. $exclude['user'] = TRUE; while (count($path_elements) > 1) { array_pop($path_elements); // Copy the path elements for up-casting. $route_request = $this->getRequestForPath(implode('/', $path_elements), $exclude); if ($route_request) { $route_name = $route_request->attributes->get(RouteObjectInterface::ROUTE_NAME); // Note that the parameters don't really matter here since we're // passing in the request which already has the upcast attributes. $parameters = array(); $access = $this->accessManager->checkNamedRoute($route_name, $parameters, $this->currentUser, $route_request); if ($access) { $title = $this->titleResolver->getTitle($route_request, $route_request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)); } if ($access) { if (!isset($title)) { // Fallback to using the raw path component as the title if the // route is missing a _title or _title_callback attribute. $title = str_replace(array('-', '_'), ' ', Unicode::ucfirst(end($path_elements))); } // @todo Replace with a #type => link render element so that the alter // hook can work with the actual data. $links[] = $this->l($title, $route_request->attributes->get(RouteObjectInterface::ROUTE_NAME), $route_request->attributes->get('_raw_variables')->all(), array('html' => TRUE)); } } } if ($path && $path != $front) { // Add the Home link, except for the front page. $links[] = $this->l($this->t('Home'), '<front>'); } return array_reverse($links); }
/** * Builds a table row for the system modules page. * * @param array $modules * The list existing modules. * @param \Drupal\Core\Extension\Extension $module * The module for which to build the form row. * @param $distribution * * @return array * The form row for the given module. */ protected function buildRow(array $modules, Extension $module, $distribution) { // Set the basic properties. $row['#required'] = array(); $row['#requires'] = array(); $row['#required_by'] = array(); $row['name']['#markup'] = $module->info['name']; $row['description']['#markup'] = $this->t($module->info['description']); $row['version']['#markup'] = $module->info['version']; // Generate link for module's help page, if there is one. $row['links']['help'] = array(); if ($this->moduleHandler->moduleExists('help') && $module->status && in_array($module->getName(), $this->moduleHandler->getImplementations('help'))) { if ($this->moduleHandler->invoke($module->getName(), 'help', array('help.page.' . $module->getName(), $this->routeMatch))) { $row['links']['help'] = array('#type' => 'link', '#title' => $this->t('Help'), '#url' => Url::fromRoute('help.page', ['name' => $module->getName()]), '#options' => array('attributes' => array('class' => array('module-link', 'module-link-help'), 'title' => $this->t('Help')))); } } // Generate link for module's permission, if the user has access to it. $row['links']['permissions'] = array(); if ($module->status && \Drupal::currentUser()->hasPermission('administer permissions') && in_array($module->getName(), $this->moduleHandler->getImplementations('permission'))) { $row['links']['permissions'] = array('#type' => 'link', '#title' => $this->t('Permissions'), '#url' => Url::fromRoute('user.admin_permissions'), '#options' => array('fragment' => 'module-' . $module->getName(), 'attributes' => array('class' => array('module-link', 'module-link-permissions'), 'title' => $this->t('Configure permissions')))); } // Generate link for module's configuration page, if it has one. $row['links']['configure'] = array(); if ($module->status && isset($module->info['configure'])) { $route_parameters = isset($module->info['configure_parameters']) ? $module->info['configure_parameters'] : array(); if ($this->accessManager->checkNamedRoute($module->info['configure'], $route_parameters, $this->currentUser)) { $links = $this->menuLinkManager->loadLinksByRoute($module->info['configure']); /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ $link = reset($links); // Most configure links have a corresponding menu link, though some just // have a route. if ($link) { $description = $link->getDescription(); } else { $request = new Request(); $request->attributes->set('_route_name', $module->info['configure']); $route_object = $this->routeProvider->getRouteByName($module->info['configure']); $request->attributes->set('_route', $route_object); $request->attributes->add($route_parameters); $description = $this->titleResolver->getTitle($request, $route_object); } $row['links']['configure'] = array('#type' => 'link', '#title' => $this->t('Configure'), '#url' => Url::fromRoute($module->info['configure'], $route_parameters), '#options' => array('attributes' => array('class' => array('module-link', 'module-link-configure'), 'title' => $description))); } } // Present a checkbox for installing and indicating the status of a module. $row['enable'] = array('#type' => 'checkbox', '#title' => $this->t('Install'), '#default_value' => (bool) $module->status, '#disabled' => (bool) $module->status); // Disable the checkbox for required modules. if (!empty($module->info['required'])) { // Used when displaying modules that are required by the installation profile $row['enable']['#disabled'] = TRUE; $row['#required_by'][] = $distribution . (!empty($module->info['explanation']) ? ' (' . $module->info['explanation'] . ')' : ''); } // Check the compatibilities. $compatible = TRUE; // Initialize an empty array of reasons why the module is incompatible. Add // each reason as a separate element of the array. $reasons = array(); // Check the core compatibility. if ($module->info['core'] != \Drupal::CORE_COMPATIBILITY) { $compatible = FALSE; $reasons[] = $this->t('This version is not compatible with Drupal !core_version and should be replaced.', array('!core_version' => \Drupal::CORE_COMPATIBILITY)); } // Ensure this module is compatible with the currently installed version of PHP. if (version_compare(phpversion(), $module->info['php']) < 0) { $compatible = FALSE; $required = $module->info['php'] . (substr_count($module->info['php'], '.') < 2 ? '.*' : ''); $reasons[] = $this->t('This module requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $required, '!php_version' => phpversion())); } // If this module is not compatible, disable the checkbox. if (!$compatible) { $status = implode(' ', $reasons); $row['enable']['#disabled'] = TRUE; $row['description']['#markup'] = $status; $row['#attributes']['class'][] = 'incompatible'; } // If this module requires other modules, add them to the array. foreach ($module->requires as $dependency => $version) { if (!isset($modules[$dependency])) { $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">missing</span>)', array('@module' => Unicode::ucfirst($dependency))); $row['enable']['#disabled'] = TRUE; } elseif (empty($modules[$dependency]->hidden)) { $name = $modules[$dependency]->info['name']; // Disable the module's checkbox if it is incompatible with the // dependency's version. if ($incompatible_version = drupal_check_incompatibility($version, str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $modules[$dependency]->info['version']))) { $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> version @version)', array('@module' => $name . $incompatible_version, '@version' => $modules[$dependency]->info['version'])); $row['enable']['#disabled'] = TRUE; } elseif ($modules[$dependency]->info['core'] != \Drupal::CORE_COMPATIBILITY) { $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> this version of Drupal core)', array('@module' => $name)); $row['enable']['#disabled'] = TRUE; } elseif ($modules[$dependency]->status) { $row['#requires'][$dependency] = $this->t('@module', array('@module' => $name)); } else { $row['#requires'][$dependency] = $this->t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $name)); } } } // If this module is required by other modules, list those, and then make it // impossible to disable this one. foreach ($module->required_by as $dependent => $version) { if (isset($modules[$dependent]) && empty($modules[$dependent]->info['hidden'])) { if ($modules[$dependent]->status == 1 && $module->status == 1) { $row['#required_by'][$dependent] = $this->t('@module', array('@module' => $modules[$dependent]->info['name'])); $row['enable']['#disabled'] = TRUE; } else { $row['#required_by'][$dependent] = $this->t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $modules[$dependent]->info['name'])); } } } return $row; }