View source
<?php
namespace Drupal\faq\Controller;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\Core\Utility\LinkGeneratorInterface;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Term;
use Drupal\faq\FaqHelper;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class FaqController extends ControllerBase {
protected $database;
protected $config;
protected $renderer;
protected $entityTypeManager;
protected $languageManager;
protected $linkGenerator;
public function __construct(Connection $database, ConfigFactoryInterface $config, RendererInterface $renderer, EntityTypeManagerInterface $entityTypeManager, LanguageManagerInterface $languageManager, LinkGeneratorInterface $linkGenerator) {
$this->database = $database;
$this->config = $config;
$this->renderer = $renderer;
$this->entityTypeManager = $entityTypeManager;
$this->languageManager = $languageManager;
$this->linkGenerator = $linkGenerator;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('database'), $container
->get('config.factory'), $container
->get('renderer'), $container
->get('entity_type.manager'), $container
->get('language_manager'), $container
->get('link_generator'));
}
public function faqPage($tid = 0, $faq_display = '', $category_display = '') {
$faq_settings = $this->config
->get('faq.settings');
$output = $output_answers = '';
$build = array();
$build['#type'] = 'markup';
$build['#attached']['library'][] = 'faq/faq-css';
$build['#title'] = $faq_settings
->get('title');
if (!$this
->moduleHandler()
->moduleExists('taxonomy')) {
$tid = 0;
}
$faq_display = $faq_settings
->get('display');
$use_categories = $faq_settings
->get('use_categories');
$category_display = $faq_settings
->get('category_display');
if (!$this
->moduleHandler()
->moduleExists('taxonomy')) {
$use_categories = FALSE;
}
if ($use_categories && $category_display == 'hide_qa' || $faq_display == 'hide_answer') {
$build['#attached']['library'][] = 'faq/faq-scripts';
$build['#attached']['drupalSettings']['faqSettings']['hide_qa_accordion'] = $faq_settings
->get('hide_qa_accordion');
$build['#attached']['drupalSettings']['faqSettings']['category_hide_qa_accordion'] = $faq_settings
->get('category_hide_qa_accordion');
}
if (!$use_categories || $category_display == 'none' && empty($tid)) {
if (!empty($tid)) {
throw new NotFoundHttpException();
}
$langcode = $this->languageManager
->getCurrentLanguage()
->getId();
$default_sorting = $faq_settings
->get('default_sorting');
$query = $this->database
->select('node', 'n');
$weight_alias = $query
->leftJoin('faq_weights', 'w', '%alias.nid=n.nid');
$query
->leftJoin('node_field_data', 'd', 'd.nid=n.nid');
$db_or = new Condition('OR');
$db_or
->condition("{$weight_alias}.tid", 0)
->isNull("{$weight_alias}.tid");
$query
->fields('n', [
'nid',
])
->condition('n.type', 'faq')
->condition('d.langcode', $langcode)
->condition('d.status', 1)
->condition($db_or)
->addTag('node_access');
$default_weight = 0;
if ($default_sorting == 'ASC') {
$default_weight = 1000000;
}
$query
->addExpression("COALESCE(w.weight, {$default_weight})", 'effective_weight');
$query
->orderBy('effective_weight', 'ASC')
->orderBy('d.sticky', 'DESC');
if ($default_sorting == 'ASC') {
$query
->orderBy('d.created', 'ASC');
}
else {
$query
->orderBy('d.created', 'DESC');
}
$nids = $query
->execute()
->fetchCol();
$data = Node::loadMultiple($nids);
foreach ($data as $key => &$node) {
$node = $node
->hasTranslation($langcode) ? $node
->getTranslation($langcode) : $node;
}
$questions_to_render = array();
$questions_to_render['#data'] = $data;
switch ($faq_display) {
case 'questions_top':
$questions_to_render['#theme'] = 'faq_questions_top';
break;
case 'hide_answer':
$questions_to_render['#theme'] = 'faq_hide_answer';
break;
case 'questions_inline':
$questions_to_render['#theme'] = 'faq_questions_inline';
break;
case 'new_page':
$questions_to_render['#theme'] = 'faq_new_page';
break;
}
$output = \Drupal::service('renderer')
->render($questions_to_render);
}
else {
$hide_child_terms = $faq_settings
->get('hide_child_terms');
if (!empty($tid)) {
if ($term = Term::load($tid)) {
$title = $faq_settings
->get('title');
$build['#title'] = $title . ($title ? ' - ' : '') . $this
->t($term
->getName());
$this
->_displayFaqByCategory($faq_display, $category_display, $term, 0, $output, $output_answers);
$to_render = array(
'#theme' => 'faq_page',
'#content' => new FormattableMarkup($output, []),
'#answers' => new FormattableMarkup($output_answers, []),
);
$build['#markup'] = $this->renderer
->render($to_render);
return $build;
}
else {
throw new NotFoundHttpException();
}
}
$list_style = $faq_settings
->get('category_listing');
$vocabularies = Vocabulary::loadMultiple();
$vocab_omit = $faq_settings
->get('omit_vocabulary');
$items = array();
$vocab_items = array();
foreach ($vocabularies as $vid => $vobj) {
if (isset($vocab_omit[$vid]) && $vocab_omit[$vid] !== 0) {
continue;
}
if ($category_display == "new_page") {
$vocab_items = $this
->_getIndentedFaqTerms($vid, 0);
$items = array_merge($items, $vocab_items);
}
else {
if ($hide_child_terms && $category_display == 'hide_qa') {
$tree = $this->entityTypeManager
->getStorage('taxonomy_term')
->loadTree($vid, 0, 1, TRUE);
}
else {
$tree = $this->entityTypeManager
->getStorage('taxonomy_term')
->loadTree($vid, 0, NULL, TRUE);
}
foreach ($tree as $term) {
switch ($category_display) {
case 'hide_qa':
case 'categories_inline':
if (FaqHelper::taxonomyTermCountNodes($term
->id())) {
$this
->_displayFaqByCategory($faq_display, $category_display, $term, 1, $output, $output_answers);
}
break;
}
}
}
}
if ($category_display == "new_page") {
$output = $this
->_renderCategoriesToList($items, $list_style);
}
}
$faq_description = $faq_settings
->get('description');
$markup = array(
'#theme' => 'faq_page',
'#content' => new FormattableMarkup($output, []),
'#answers' => new FormattableMarkup($output_answers, []),
'#description' => new FormattableMarkup($faq_description, []),
);
$build['#markup'] = $this->renderer
->render($markup);
return $build;
}
public function orderPage($tid = NULL) {
$faq_settings = $this->config
->get('faq.settings');
$build = array();
$build['#attached']['library'][] = 'faq/faq-scripts';
$build['#attached']['drupalSettings']['faqSettings']['hide_qa_accordion'] = $faq_settings
->get('hide_qa_accordion');
$build['#attached']['drupalSettings']['faqSettings']['category_hide_qa_accordion'] = $faq_settings
->get('category_hide_qa_accordion');
$build['#attached']['library'][] = 'faq/faq-css';
$build['faq_order'] = $this
->formBuilder()
->getForm('Drupal\\faq\\Form\\OrderForm');
return $build;
}
public function generalSettings() {
$build = array();
$build['faq_general_settings_form'] = $this
->formBuilder()
->getForm('Drupal\\faq\\Form\\GeneralForm');
return $build;
}
public function questionsSettings() {
$faq_settings = $this->config
->get('faq.settings');
$build = array();
$build['#attached']['library'][] = 'faq/faq-scripts';
$build['#attached']['drupalSettings']['faqSettings']['hide_qa_accordion'] = $faq_settings
->get('hide_qa_accordion');
$build['#attached']['drupalSettings']['faqSettings']['category_hide_qa_accordion'] = $faq_settings
->get('category_hide_qa_accordion');
$build['faq_questions_settings_form'] = $this
->formBuilder()
->getForm('Drupal\\faq\\Form\\QuestionsForm');
return $build;
}
public function categoriesSettings() {
$faq_settings = $this->config
->get('faq.settings');
$build = array();
$build['#attached']['library'][] = 'faq/faq-scripts';
$build['#attached']['drupalSettings']['faqSettings']['hide_qa_accordion'] = $faq_settings
->get('hide_qa_accordion');
$build['#attached']['drupalSettings']['faqSettings']['category_hide_qa_accordion'] = $faq_settings
->get('category_hide_qa_accordion');
if (!$this
->moduleHandler()
->moduleExists('taxonomy')) {
$this
->messenger()
->addError(t('Categorization of questions will not work without the "taxonomy" module being enabled.'));
}
$build['faq_categories_settings_form'] = $this
->formBuilder()
->getForm('Drupal\\faq\\Form\\CategoriesForm');
return $build;
}
private function _displayFaqByCategory($faq_display, $category_display, $term, $display_header, &$output, &$output_answers) {
$langcode = $this->languageManager
->getCurrentLanguage()
->getId();
$default_sorting = $this->config
->get('faq.settings')
->get('default_sorting');
$term_id = $term
->id();
$query = $this->database
->select('node', 'n');
$query
->join('node_field_data', 'd', 'd.nid = n.nid');
$query
->innerJoin('taxonomy_index', 'ti', 'n.nid = ti.nid');
$query
->leftJoin('faq_weights', 'w', 'w.tid = ti.tid AND n.nid = w.nid');
$query
->fields('n', [
'nid',
])
->condition('n.type', 'faq')
->condition('d.langcode', $langcode)
->condition('d.status', 1)
->condition("ti.tid", $term_id)
->addTag('node_access');
$default_weight = 0;
if ($default_sorting == 'ASC') {
$default_weight = 1000000;
}
$query
->addExpression("COALESCE(w.weight, {$default_weight})", 'effective_weight');
$query
->orderBy('effective_weight', 'ASC')
->orderBy('d.sticky', 'DESC');
if ($default_sorting == 'ASC') {
$query
->orderBy('d.created', 'ASC');
}
else {
$query
->orderBy('d.created', 'DESC');
}
$nids = $query
->execute()
->fetchCol();
$data = Node::loadMultiple($nids);
foreach ($data as $key => &$node) {
$node = $node
->hasTranslation($langcode) ? $node
->getTranslation($langcode) : $node;
}
$depth = 0;
if (!isset($term->depth)) {
$children = $this->entityTypeManager
->getStorage('taxonomy_term')
->loadChildren($term
->id());
$term->depth = count($children);
}
while ($depth < $term->depth) {
$display_header = 1;
$indent = '<div class="faq-category-indent">';
$output .= $indent;
$depth++;
}
$faq_class = "faq-qa";
if ($category_display == "hide_qa") {
$faq_class = "faq-qa-hide";
}
$output_render = $output_answers_render = array(
'#data' => $data,
'#display_header' => $display_header,
'#category_display' => $category_display,
'#term' => $term,
'#class' => $faq_class,
'#parent_term' => $term,
);
switch ($faq_display) {
case 'questions_top':
$output_render['#theme'] = 'faq_category_questions_top';
$output .= $this->renderer
->render($output_render);
$output_answers_render['#theme'] = 'faq_category_questions_top_answers';
$output_answers .= $this->renderer
->render($output_answers_render);
break;
case 'hide_answer':
$output_render['#theme'] = 'faq_category_hide_answer';
$output .= $this->renderer
->render($output_render);
break;
case 'questions_inline':
$output_render['#theme'] = 'faq_category_questions_inline';
$output .= $this->renderer
->render($output_render);
break;
case 'new_page':
$output_render['#theme'] = 'faq_category_new_page';
$output .= $this->renderer
->render($output_render);
break;
}
while ($depth > 0) {
$output .= '</div>';
$depth--;
}
}
private function _getIndentedFaqTerms($vid, $tid) {
$faq_settings = $this->config
->get('faq.settings');
$display_faq_count = $faq_settings
->get('count');
$hide_child_terms = $faq_settings
->get('hide_child_terms');
$items = array();
$tree = $this->entityTypeManager
->getStorage('taxonomy_term')
->loadTree($vid, $tid, 1, TRUE);
foreach ($tree as $term) {
$term_id = $term
->id();
$tree_count = FaqHelper::taxonomyTermCountNodes($term_id);
if ($tree_count) {
$desc = '';
$term_description = $term
->getDescription();
if (!empty($term_description)) {
$desc = '<div class="faq-qa-description">';
$desc .= $term_description . "</div>";
}
$query = $this->database
->select('node', 'n');
$query
->join('node_field_data', 'd', 'n.nid = d.nid');
$query
->innerJoin('taxonomy_index', 'ti', 'n.nid = ti.nid');
$term_node_count = $query
->condition('d.status', 1)
->condition('n.type', 'faq')
->condition("ti.tid", $term_id)
->addTag('node_access')
->countQuery()
->execute()
->fetchField();
if ($term_node_count > 0) {
$path = Url::fromUserInput('/faq-page/' . $term_id);
if ($display_faq_count) {
$count = $term_node_count;
if ($hide_child_terms) {
$count = $tree_count;
}
$cur_item = $this->linkGenerator
->generate($this
->t($term
->getName()), $path) . " ({$count}) " . $desc;
}
else {
$cur_item = $this->linkGenerator
->generate($this
->t($term
->getName()), $path) . $desc;
}
}
else {
$cur_item = $this
->t($term
->getName()) . $desc;
}
if (!empty($term_image)) {
$cur_item .= '<div class="clear-block"></div>';
}
$term_items = array();
if (!$hide_child_terms) {
$term_items = $this
->_getIndentedFaqTerms($vid, $term_id);
}
$items[] = array(
"item" => $cur_item,
"children" => $term_items,
);
}
}
return $items;
}
private function _renderCategoriesToList($items, $list_style) {
$list = array();
foreach ($items as $item) {
$pre = '';
if (!empty($item['children'])) {
$pre = $this
->_renderCategoriesToList($item['children'], $list_style);
}
$list[] = new FormattableMarkup($item['item'] . $pre, []);
}
$render = array(
'#theme' => 'item_list',
'#items' => $list,
'#list_style' => $list_style,
);
return $this->renderer
->render($render);
}
}