diff --git a/asklib.info.yml b/asklib.info.yml index d67e68a..68c6f4a 100644 --- a/asklib.info.yml +++ b/asklib.info.yml @@ -4,12 +4,13 @@ core: 8.x package: Kirjastot.fi description: "Kysy kirjastonhoitajalta" configure: asklib.admin +core_version_requirement: ">=8" dependencies: - autoslug - finto_taxonomy - forum - kifiform - - kifimail + - symfony_mailer - kifisearch - kifistats - language diff --git a/asklib.install b/asklib.install index e12fbbc..6210518 100644 --- a/asklib.install +++ b/asklib.install @@ -7,7 +7,7 @@ use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\StringTranslation\TranslatableMarkup; function asklib_install() { - $em = Drupal::entityManager(); + $em = \Drupal::service('entity_type.manager'); $em->getStorage('field_storage_config')->create([ 'entity_type' => 'asklib_question', @@ -58,7 +58,7 @@ function asklib_update_8002() { $entity = \Drupal::entityTypeManager()->getStorage('entity_form_mode')->load('asklib_question.edit'); if(!$entity) { // If not load and write the configuration to Drupal config. - $config_path = drupal_get_path('module', 'asklib') . '/config/install'; + $config_path = \Drupal::service('extension.list.module')->getPath('asklib') . '/config/install'; $source = new FileStorage($config_path); $config_storage = \Drupal::service('config.storage'); $config_storage->write('core.entity_form_mode.asklib_question.edit', $source->read('core.entity_form_mode.asklib_question.edit')); diff --git a/asklib.libraries.yml b/asklib.libraries.yml index e33b428..55df9e1 100644 --- a/asklib.libraries.yml +++ b/asklib.libraries.yml @@ -17,6 +17,9 @@ question-edit-form: js: public/js/toggle-answered.js: {} public/js/kifiform-tags-custom.js: {} + dependencies: + - core/jquery + - core/once field-target-library: css: component: diff --git a/asklib.module b/asklib.module index 4cd9727..b3badde 100644 --- a/asklib.module +++ b/asklib.module @@ -1,5 +1,9 @@ setFormClass('asklib_admin', \Drupal\asklib\Form\MailGroupTermForm::class); + $term->setFormClass('asklib_admin', MailGroupTermForm::class); $term->setLinkTemplate('asklib-mail-group-form', '/admin/config/asklib/emails/{taxonomy_term}'); } if (isset($entity_types['user'])) { $user = $entity_types['user']; - $user->setFormClass('asklib_admin', \Drupal\asklib\Form\MailGroupUserForm::class); + $user->setFormClass('asklib_admin', MailGroupUserForm::class); $user->setLinkTemplate('asklib-mail-group-form', '/admin/config/asklib/emails/users/{user}'); } } @@ -112,8 +118,9 @@ function asklib_mail($key, &$message, $params) { function asklib_cron() { $day_limit = Drupal::config('asklib.settings')->get('reserved_window'); $date_limit = date('Y-m-d', strtotime(sprintf('-%d days', $day_limit))); - $storage = Drupal::entityManager()->getStorage('asklib_question'); + $storage = \Drupal::service('entity_type.manager')->getStorage('asklib_question'); $qids = $storage->getQuery() + ->accessCheck(FALSE) ->condition('state', QuestionInterface::STATE_RESERVED) ->execute(); $questions = $storage->loadMultiple($qids); @@ -146,7 +153,7 @@ function _asklib_clear_old_question_contact_info() { $two_years_ago = mktime(1, 0, 0, date("m"), date("d"), date("Y") - 2); $storage = \Drupal::entityTypeManager()->getStorage('asklib_question'); - $query = $storage->getQuery(); + $query = $storage->getQuery()->accessCheck(FALSE); $info_not_cleared = $query->orConditionGroup() ->exists('email') ->condition('name', 'Kysyjätieto poistettu', '<>'); @@ -267,8 +274,9 @@ function asklib_views_query_alter(ViewExecutable $view, QueryPluginBase $query) function asklib_bug_fix_rss_query(array &$conditions) { foreach ($conditions as &$rule) { if (is_array($rule)) { - if ($rule['field'] instanceof \Drupal\Core\Database\Query\ConditionInterface) { - asklib_bug_fix_rss_query($rule['field']->conditions()); + if ($rule['field'] instanceof ConditionInterface) { + $conditions = $rule['field']->conditions(); + asklib_bug_fix_rss_query($conditions); } elseif (is_string($rule['field'])) { if (trim($rule['field']) == 'asklib_question__feeds.feeds = :asklib_question__feeds_feeds') { $rule['field'] = 'asklib_question__feeds.feeds_target_id = :asklib_question__feeds_feeds'; @@ -280,7 +288,8 @@ function asklib_bug_fix_rss_query(array &$conditions) { function asklib_views_pre_execute(ViewExecutable $view) { if ($view->storage->id() == 'asklib_rss') { - asklib_bug_fix_rss_query($view->build_info['query']->conditions()); + $conditions = $view->build_info['query']->conditions(); + asklib_bug_fix_rss_query($conditions); } } @@ -306,6 +315,19 @@ function asklib_form_alter(&$form, FormStateInterface $form_state, $form_id) { } } +function asklib_form_asklib_question_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) { + if ( + isset($form['municipality']['widget']['#options']) && + is_array($form['municipality']['widget']['#options']) + ) { + $options = $form['municipality']['widget']['#options']; + uasort($options, function ($a, $b) { + return strcoll($a, $b); // Locale-aware string comparison + }); + $form['municipality']['widget']['#options'] = $options; + } +} + function asklib_preprocess_views_view_table(&$variables) { if ($variables['view']->id() != 'asklib_index') { return; @@ -390,6 +412,14 @@ function asklib_preprocess_asklib_question(&$variables) { 'resource' => 'https://www.kirjastot.fi/kysy/' . $variables['elements']['#asklib_question']->id(), ]; + /** + * NOTE: These fields should be hidden from Drupal's built-in display management form. + * Currently, asklib does not provide one. Asklib question has only one view mode called "full". + * For future development, we could implement view support for asklib_question and asklib_answer. + */ + unset($variables['question']['municipality']); + unset($variables['question']['user']); + $variables['question']['title_meta'] = [ '#weight' => -1000, '#theme' => 'rdf_metadata', @@ -418,6 +448,9 @@ function asklib_preprocess_asklib_answer(&$variables) { $variables['content'][$key] = $variables['elements'][$key]; } + // See the NOTE in asklib_preprocess_asklib_question about display managment. + unset($variables['content']['created']); + $view = Drupal::entityTypeManager()->getViewBuilder('asklib_question'); $displays = $variables['elements']['#asklib_answer']->getQuestion()->get('displays'); $rendered = $view->viewField($displays, $displays->getFieldDefinition()->getDisplayOptions('view')); @@ -447,13 +480,25 @@ function asklib_form_comment_comment_asklib_form_alter(&$form, FormStateInterfac $form['field_email']['widget'][0]['value']['#attributes']['autocomplete'] = 'email'; } -function asklib_user_login($account) { - $route_name = Drupal::routeMatch()->getRouteName(); +/** + * Implements hook_form_FORM_ID_alter(). + */ +function asklib_form_user_login_form_alter(&$form, FormStateInterface $form_state) { + $form['#submit'][] = 'asklib_user_login_submit'; +} + +/** + * Form submission handler for user_login_form(). + * + * Redirects the user to the asklib dashboard user can answer questions. + */ +function asklib_user_login_submit(&$form, FormStateInterface $form_state) { + $account = Drupal::currentUser(); // Redirect only when request comes from the login form. - if ($route_name == 'user.login' && $account->hasPermission('answer questions')) { - $url = Url::fromRoute('asklib.admin_index')->toString(); - RedirectResponse::create($url)->send(); + if ($account->hasPermission('answer questions')) { + $url = Url::fromRoute('asklib.admin_index'); + $form_state->setRedirectUrl($url); } } @@ -463,7 +508,7 @@ function asklib_user_update(UserInterface $user) { } } -function asklib_system_info_alter(array &$info, \Drupal\Core\Extension\Extension $file, $type) { +function asklib_system_info_alter(array &$info, Extension $file, $type) { if ($type != 'theme' || !in_array($file->getName(), ['seven', 'kifi_admin'])) { return; } @@ -560,7 +605,7 @@ function asklib_tokens($type, array $tokens, array $data, array $options, Bubble } if ($type == 'asklib_answer') { - $answer = isset($data['asklib_answer']) ? $data['asklib_answer'] : $data['asklib_question']->getAnswer(); + $answer = $data['asklib_answer'] ?? $data['asklib_question']->getAnswer(); if ($answer) { foreach ($tokens as $name => $original) { @@ -615,12 +660,13 @@ function asklib_preprocess_html(array &$variables) { if (!$user->get('field_asklib_library')->target_id) { $url = Url::fromRoute('entity.user.asklib_mail_group_form', ['user' => $user->id()])->toString(); - drupal_set_message(t('Changes to Ask a Librarian: Set your home library in settings.', [':url' => $url]), 'warning'); + \Drupal::messenger()->addWarning(t('Changes to Ask a Librarian: Set your home library in settings.', [':url' => $url])); } } } function asklib_toolbar() { + $items = []; $items['asklib'] = [ '#type' => 'toolbar_item', '#weight' => 200, @@ -750,10 +796,14 @@ function asklib_asklib_question_delete(QuestionInterface $question) { /* * NOTE: Makes deleting questions in hordes veeeery slow! */ - $url = Url::fromRoute('entity.asklib_question.canonical', ['asklib_question' => $question->id()]); - Drupal::service('path.alias_storage')->delete(['source' => $url]); + $path = '/asklib_question/' . $question->id(); + + // Drupal::service('path.alias_storage')->delete(['source' => $url]); + $aliases = Drupal::service('entity_type.manager')->getStorage('path_alias')->loadByProperties(['path' => $path]); + foreach ($aliases as $alias) { + $alias->delete(); + } - search_index_clear('asklib_search_elastic', $question->id()); } function asklib_delete_question_index(QuestionInterface $question) { @@ -768,10 +818,8 @@ function asklib_delete_question_index(QuestionInterface $question) { 'type' => 'content', 'id' => sprintf('asklib_question:%d:%s', $question->id(), $language->getId()) ]); - } catch (\Elasticsearch\Common\Exceptions\Missing404Exception $e) { - // Question was not indexed before, pass. - } catch (\Elasticsearch\Common\Exceptions\NoNodesAvailableException $e) { - // Elasticsearch is down (or not installed), pass. + } catch (\Exception $e) { + \Drupal::logger('asklib')->error($e->getMessage()); } } } @@ -794,3 +842,10 @@ function asklib_build_question_index(QuestionInterface $question) { ->execute(); } } +function asklib_mailer_post_render(EmailInterface $email) { + $do_not_send = $email->getParam('do_not_send'); + if ($do_not_send) + { + throw new SkipMailException(); + } +} diff --git a/asklib.routing.yml b/asklib.routing.yml index 56bdfcd..bc9fc11 100644 --- a/asklib.routing.yml +++ b/asklib.routing.yml @@ -81,7 +81,7 @@ asklib.admin_email_groups: _controller: 'Drupal\asklib\Controller\MailGroupController::groups' requirements: _permission: 'administer asklib' -asklib.admin_email_groups: +asklib.admin_email_single_group: path: '/admin/config/asklib/emails/groups/{taxonomy_term}' defaults: _title: 'Email groups' diff --git a/asklib.services.yml b/asklib.services.yml index 887af17..625022c 100644 --- a/asklib.services.yml +++ b/asklib.services.yml @@ -24,7 +24,7 @@ services: - { name: cache.context } asklib.breadcrumb.default: class: Drupal\system\PathBasedBreadcrumbBuilder - arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current'] + arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current', '@path.matcher'] tags: - { name: asklib_breadcrumb, priority: 0 } asklib.breadcrumb.archive: @@ -34,17 +34,17 @@ services: - { name: asklib_breadcrumb, priority: 100 } asklib.breadcrumb.question_from_collection: class: 'Drupal\asklib\Breadcrumb\QuestionFromCollectionCrumb' - arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current', '@request_stack', '@entity_type.manager'] + arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current', '@path.matcher', '@request_stack', '@entity_type.manager'] tags: - { name: asklib_breadcrumb, priority: 200 } asklib.breadcrumb.collection_from_keyword_index: class: 'Drupal\asklib\Breadcrumb\QuestionFromKeywordIndexCrumb' - arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current', '@request_stack', '@entity_type.manager'] + arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current', '@path.matcher', '@request_stack', '@entity_type.manager'] tags: - { name: asklib_breadcrumb, priority: 200 } asklib.breadcrumb.taxonomy: class: 'Drupal\asklib\Breadcrumb\TaxonomyCrumb' - arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current', '@request_stack'] + arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current', '@path.matcher', '@request_stack'] tags: - { name: asklib_breadcrumb, priority: 200 } asklib.breadcrumb_proxy: diff --git a/composer.json b/composer.json index e571b79..6c93734 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,6 @@ "type": "drupal-module", "license": "GPL-2.0+", "require": { - "html2text/html2text": "^4.0", - "elasticsearch/elasticsearch": "^5.3" + "html2text/html2text": "^4.0" } } diff --git a/config/mailer_override/symfony_mailer.mailer_policy.asklib.answer.yml b/config/mailer_override/symfony_mailer.mailer_policy.asklib.answer.yml new file mode 100644 index 0000000..3c1b4a1 --- /dev/null +++ b/config/mailer_override/symfony_mailer.mailer_policy.asklib.answer.yml @@ -0,0 +1,13 @@ +langcode: fi +status: true +dependencies: + module: + - asklib +id: asklib.answer +configuration: + email_subject: + value: 'Vastaus Kysy kirjastonhoitajalta -palvelusta' + email_body: + content: + value: "

Hei!

\r\n

Vastaus Kysy kirjastonhoitajalta -palveluun lähettämääsi kysymykseen.

\r\n\r\n
\r\n

[asklib_answer:body]

\r\n {% if has_answer_details %}\r\n

[asklib_answer:details]

\r\n {% endif %}\r\n {% if is_admin %}\r\n [asklib_answer:author], Kirjastot.fi-toimitus\r\n {% else %}\r\n [asklib_answer:author], [asklib_answer:library]\r\n {% endif %}\r\n
\r\n

[asklib_question:body]

\r\n {% if has_question_details %}\r\n

[asklib_question:details]

\r\n {% endif %}\r\n
\r\n\r\n \r\n\r\n

\r\n

[asklib_answer:signature]

\r\n
" + format: email_html diff --git a/config/mailer_override/symfony_mailer.mailer_policy.asklib.new_question.yml b/config/mailer_override/symfony_mailer.mailer_policy.asklib.new_question.yml new file mode 100644 index 0000000..ede3b42 --- /dev/null +++ b/config/mailer_override/symfony_mailer.mailer_policy.asklib.new_question.yml @@ -0,0 +1,13 @@ +langcode: fi +status: true +dependencies: + module: + - asklib +id: asklib.new_question +configuration: + email_subject: + value: '[Kysy kirjastonhoitajalta] Kuittaus vastaanotetusta kysymyksestä (asiakas)' + email_body: + content: + value: "

Hei!

\r\n

Kiitos kysymyksestäsi. Vastaamme siihen kolmen työpäivän kuluessa. Vastaamme vain tietopalvelukysymyksiin. Käytämme kirjaston käytössä olevia lähteitä ja vastaamme kirjastoammattilaisen osaamisella. Kirjastot.fi-toimitus, toimitus@kirjastot.fi.

\r\n
\r\n [asklib_question:email]\r\n

[asklib_question:body]

\r\n
" + format: email_html diff --git a/config/mailer_override/symfony_mailer.mailer_policy.asklib.new_question_admin.yml b/config/mailer_override/symfony_mailer.mailer_policy.asklib.new_question_admin.yml new file mode 100644 index 0000000..b516d80 --- /dev/null +++ b/config/mailer_override/symfony_mailer.mailer_policy.asklib.new_question_admin.yml @@ -0,0 +1,13 @@ +langcode: fi +status: true +dependencies: + module: + - asklib +id: asklib.new_question_admin +configuration: + email_subject: + value: '[Kysy kirjastonhoitajalta] Ilmoitus uudesta kysymyksestä (vastaajat)' + email_body: + content: + value: "

Kirjastonne alueelta on saapunut uusi kysymys vastattavaksi Kysy kirjastonhoitajalta -palveluun. Kirjaudu osoitteessa https://www.kirjastot.fi/user/login

\r\n

Odottavat kysymykset

\r\n
\r\n [asklib_question:email]\r\n

[asklib_question:body]

\r\n
\r\n" + format: email_html diff --git a/config/optional/search.page.asklib_question_elastic.yml b/config/optional/search.page.asklib_question_elastic.yml deleted file mode 100644 index 19f1d2f..0000000 --- a/config/optional/search.page.asklib_question_elastic.yml +++ /dev/null @@ -1,12 +0,0 @@ -uuid: a9ae4234-3efd-48fd-80b9-863a8f7455a0 -langcode: en -status: true -dependencies: - module: - - asklib -id: asklib_question_elastic -label: 'Ask a Librarian' -path: asklib -weight: -10 -plugin: asklib_search_elastic -configuration: { } diff --git a/config/schema/asklib.schema.yml b/config/schema/asklib.schema.yml new file mode 100644 index 0000000..4c94db0 --- /dev/null +++ b/config/schema/asklib.schema.yml @@ -0,0 +1,3 @@ +entity_reference_selection.asklib_question_municipality_selection: + type: entity_reference_selection.default + label: 'Question municipality selection handler settings' diff --git a/public/js/kifiform-tags-custom.js b/public/js/kifiform-tags-custom.js index 73ac3cf..cdc296e 100644 --- a/public/js/kifiform-tags-custom.js +++ b/public/js/kifiform-tags-custom.js @@ -1,10 +1,8 @@ (function($) { "use strict"; - $("form.asklib-question-edit-form input.form-autocomplete") - .once("asklib-tag-insert") + $(once("asklib-tag-insert", "form.asklib-question-edit-form input.form-autocomplete")) .on("kififormtaginsert", function(event, ui) { - console.log(event); if (ui.item.autocompleted == true) { // This is valid as long autocomplete is configured to match only Finto terms. diff --git a/src/AnswerListBuilder.php b/src/AnswerListBuilder.php index d635864..0093c89 100644 --- a/src/AnswerListBuilder.php +++ b/src/AnswerListBuilder.php @@ -17,7 +17,7 @@ class AnswerListBuilder extends EntityListBuilder public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { return new static( $entity_type, - $container->get('entity.manager')->getStorage($entity_type->id()), + $container->get('entity_type.manager')->getStorage($entity_type->id()), $container->get('current_user') ); } @@ -45,10 +45,10 @@ public function buildRow(EntityInterface $answer) $row['answer']['data'] = [ '#type' => 'link', '#title' => $this->trimTitle($answer->getBody(), 80), - '#url' => $answer->urlInfo(), + '#url' => $answer->toUrl(), ]; $row['rating'] = $answer->getRating(); - $row['created'] = format_date($answer->getCreatedTime(), 'short'); + $row['created'] = \Drupal::service('date.formatter')->format($answer->getCreatedTime(), 'short'); $row += parent::buildRow($answer); @@ -82,12 +82,12 @@ protected function getDefaultOperations(EntityInterface $answer) // } $ops['edit'] = [ 'title' => $this->t('Edit'), - 'url' => $answer->urlInfo('edit-form'), + 'url' => $answer->toUrl('edit-form'), 'weight' => 5, ]; $ops['delete'] = [ 'title' => $this->t('Delete'), - 'url' => $answer->urlInfo('delete-form'), + 'url' => $answer->toUrl('delete-form'), 'weight' => 10, ]; return $ops; diff --git a/src/Breadcrumb/QuestionArchiveCrumb.php b/src/Breadcrumb/QuestionArchiveCrumb.php index 2e82ef4..08969e6 100644 --- a/src/Breadcrumb/QuestionArchiveCrumb.php +++ b/src/Breadcrumb/QuestionArchiveCrumb.php @@ -81,7 +81,7 @@ protected function from() { if (isset(self::$sourcePages[$from])) { $route = self::$sourcePages[$from]; - list(, $view_id, $display_id) = explode('.', $route); + [, $view_id, $display_id] = explode('.', $route); $view = \Drupal::entityTypeManager()->getStorage('view')->load($view_id); $display = $view->getDisplay($display_id); diff --git a/src/Breadcrumb/QuestionFromCollectionCrumb.php b/src/Breadcrumb/QuestionFromCollectionCrumb.php index 24d4311..8ca62d3 100644 --- a/src/Breadcrumb/QuestionFromCollectionCrumb.php +++ b/src/Breadcrumb/QuestionFromCollectionCrumb.php @@ -15,6 +15,8 @@ use Drupal\Core\Path\CurrentPathStack; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Matcher\RequestMatcherInterface; +use Drupal\Core\Path\PathMatcherInterface; +use Drupal\Core\Cache\CacheableMetadata; class QuestionFromCollectionCrumb extends PathBasedBreadcrumbBuilder { protected $requestStack; @@ -22,20 +24,20 @@ class QuestionFromCollectionCrumb extends PathBasedBreadcrumbBuilder { public static function collectionIdFromQuery($from) { // Variable value should be 'collection/{nid}' - list($foo, $nid) = explode('/', $from . '//'); + [$foo, $nid] = explode('/', $from . '//'); if ($foo == 'collection' && ctype_digit($nid)) { return $nid; } } - public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path, RequestStack $request_stack, EntityTypeManagerInterface $entity_manager) { - parent::__construct($context, $access_manager, $router, $path_processor, $config_factory, $title_resolver, $current_user, $current_path); - $this->requestStack = $request_stack; - $this->nodeStorage = $entity_manager->getStorage('node'); - } + public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path, ?PathMatcherInterface $path_matcher = NULL, RequestStack $request_stack, EntityTypeManagerInterface $entity_manager) { + parent::__construct($context, $access_manager, $router, $path_processor, $config_factory, $title_resolver, $current_user, $current_path, $path_matcher); + $this->requestStack = $request_stack; + $this->nodeStorage = $entity_manager->getStorage('node'); + } - public function applies(RouteMatchInterface $route_match) { + public function applies(RouteMatchInterface $route_match, ?CacheableMetadata $cacheable_metadata = NULL) { return ctype_digit(self::collectionIdFromQuery($this->from())); } @@ -48,7 +50,7 @@ public function build(RouteMatchInterface $route_match) { $node = reset($nodes); - $request = $this->getRequestForPath($node->url(), []); + $request = $this->getRequestForPath($node->toUrl()->toString(), []); $this->context->fromRequest($request); $crumb = parent::build($route_match); diff --git a/src/Breadcrumb/QuestionFromKeywordIndexCrumb.php b/src/Breadcrumb/QuestionFromKeywordIndexCrumb.php index c45995e..601caa1 100644 --- a/src/Breadcrumb/QuestionFromKeywordIndexCrumb.php +++ b/src/Breadcrumb/QuestionFromKeywordIndexCrumb.php @@ -15,6 +15,8 @@ use Drupal\Core\Path\CurrentPathStack; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Matcher\RequestMatcherInterface; +use Drupal\Core\Path\PathMatcherInterface; +use Drupal\Core\Cache\CacheableMetadata; class QuestionFromKeywordIndexCrumb extends PathBasedBreadcrumbBuilder { protected $requestStack; @@ -22,20 +24,19 @@ class QuestionFromKeywordIndexCrumb extends PathBasedBreadcrumbBuilder { public static function termIdFromQuery($from) { // Variable value should be 'term/{tid}' - list($foo, $tid) = explode('/', $from . '//'); + [$foo, $tid] = explode('/', $from . '//'); if ($foo == 'term' && ctype_digit($tid)) { return $tid; } } - public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path, RequestStack $request_stack, EntityTypeManagerInterface $entity_manager) { - parent::__construct($context, $access_manager, $router, $path_processor, $config_factory, $title_resolver, $current_user, $current_path); - - $this->requestStack = $request_stack; - $this->termStorage = $entity_manager->getStorage('taxonomy_term'); - } + public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path, ?PathMatcherInterface $path_matcher = NULL, RequestStack $request_stack, EntityTypeManagerInterface $entity_manager) { + parent::__construct($context, $access_manager, $router, $path_processor, $config_factory, $title_resolver, $current_user, $current_path, $path_matcher); + $this->requestStack = $request_stack; + $this->termStorage = $entity_manager->getStorage('taxonomy_term'); + } - public function applies(RouteMatchInterface $route_match) { + public function applies(RouteMatchInterface $route_match, ?CacheableMetadata $cacheable_metadata = NULL) { return ctype_digit(self::termIdFromQuery($this->from())); } @@ -48,7 +49,7 @@ public function build(RouteMatchInterface $route_match) { if (!empty($terms)) { $term = reset($terms); - if ($request = $this->getRequestForPath($term->url(), [])) { + if ($request = $this->getRequestForPath($term->toUrl()->toString(), [])) { $this->context->fromRequest($request); } $crumb = parent::build($route_match); diff --git a/src/Breadcrumb/TaxonomyCrumb.php b/src/Breadcrumb/TaxonomyCrumb.php index 2a92583..cedf76f 100644 --- a/src/Breadcrumb/TaxonomyCrumb.php +++ b/src/Breadcrumb/TaxonomyCrumb.php @@ -16,6 +16,8 @@ use Drupal\system\PathBasedBreadcrumbBuilder; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Matcher\RequestMatcherInterface; +use Drupal\Core\Path\PathMatcherInterface; +use Drupal\Core\Cache\CacheableMetadata; class TaxonomyCrumb extends PathBasedBreadcrumbBuilder { protected $requestStack; @@ -49,24 +51,23 @@ public static function fixLinkTitles(RouteMatchInterface $route_match, Breadcrum if (isset($links[3])) { // By default This link has the same title as the previous one. Rewrite it to make more sense. - $parts = explode('/', $route_match->getParameter('taxonomy_term')->url()); + $parts = explode('/', $route_match->getParameter('taxonomy_term')->toUrl()->toString()); $letter = strtoupper($parts[count($parts) - 2]); - $links[3]->setText(t('Letter @letter', ['@letter' => $letter]), $links[3]->getText()); + $links[3]->setText(t('Letter @letter', ['@letter' => $letter])); } return $crumb; } - public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path, RequestStack $request_stack) { - parent::__construct($context, $access_manager, $router, $path_processor, $config_factory, $title_resolver, $current_user, $current_path); - - $this->requestStack = $request_stack; - } + public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path, ?PathMatcherInterface $path_matcher = NULL, RequestStack $request_stack) { + parent::__construct($context, $access_manager, $router, $path_processor, $config_factory, $title_resolver, $current_user, $current_path, $path_matcher); + $this->requestStack = $request_stack; + } - public function applies(RouteMatchInterface $route_match) { + public function applies(RouteMatchInterface $route_match, ?CacheableMetadata $cacheable_metadata = NULL) { if (in_array($route_match->getRouteName(), $this->allowedRoutes)) { if ($route_match->getRouteName() == 'entity.taxonomy_term.canonical') { - $vid = $route_match->getParameter('taxonomy_term')->getVocabularyId(); + $vid = $route_match->getParameter('taxonomy_term')->bundle(); return in_array($vid, $this->allowedVocabularies); } return TRUE; diff --git a/src/Controller/AdminController.php b/src/Controller/AdminController.php index cf4eba3..0c16191 100755 --- a/src/Controller/AdminController.php +++ b/src/Controller/AdminController.php @@ -2,6 +2,7 @@ namespace Drupal\asklib\Controller; +use Drupal\Core\Database\Database; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Config\ConfigFactoryInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -23,7 +24,7 @@ public function index() { $help = check_markup($this->config->get('help'), $this->config->get('help_format')); if (isset($_GET['create_index'])) { - $query = \Drupal\Core\Database\Database::getConnection()->select('asklib_questions', 'a') + $query = Database::getConnection()->select('asklib_questions', 'a') ->distinct() ->fields('a', ['id']) ->condition('published', 1) diff --git a/src/Controller/MailGroupController.php b/src/Controller/MailGroupController.php index 2a80115..c09b4ef 100755 --- a/src/Controller/MailGroupController.php +++ b/src/Controller/MailGroupController.php @@ -28,14 +28,14 @@ public function showGroup($taxonomy_term) private function getGroupListBuilder() { $container = \Drupal::getContainer(); - $type = $this->entityManager()->getDefinition('taxonomy_term'); + $type = \Drupal::service('entity_type.manager')->getDefinition('taxonomy_term'); return MailGroupListBuilder::createInstance($container, $type); } private function getUserListBuilder() { $container = \Drupal::getContainer(); - $type = $this->entityManager()->getDefinition('user'); + $type = \Drupal::service('entity_type.manager')->getDefinition('user'); return MailUserListBuilder::createInstance($container, $type); } } diff --git a/src/Controller/MailUserController.php b/src/Controller/MailUserController.php index 16acf81..3ab783f 100644 --- a/src/Controller/MailUserController.php +++ b/src/Controller/MailUserController.php @@ -15,15 +15,15 @@ public function showUser($user) private function getGroupListBuilder() { - $type = $this->entityManager()->getDefinition('taxonomy_term'); - $storage = $this->entityManager()->getStorage('taxonomy_term'); + $type = \Drupal::service('entity_type.manager')->getDefinition('taxonomy_term'); + $storage = \Drupal::service('entity_type.manager')->getStorage('taxonomy_term'); return new MailGroupListBuilder($type, $storage); } private function getUserListBuilder() { - $type = $this->entityManager()->getDefinition('user'); - $storage = $this->entityManager()->getStorage('user'); + $type = \Drupal::service('entity_type.manager')->getDefinition('user'); + $storage = \Drupal::service('entity_type.manager')->getStorage('user'); return new MailUserListBuilder($type, $storage); } } diff --git a/src/Controller/MeteorCompatibilityController.php b/src/Controller/MeteorCompatibilityController.php index 346e8f6..053983e 100644 --- a/src/Controller/MeteorCompatibilityController.php +++ b/src/Controller/MeteorCompatibilityController.php @@ -28,7 +28,7 @@ public function redirectToQuestion($uuid) { $question = reset($result); if ($question && $question->access('view')) { - header('Location: ' . $question->url()); + header('Location: ' . $question->toUrl()->toString()); exit; } else { throw new NotFoundHttpException; diff --git a/src/Controller/QuestionViewController.php b/src/Controller/QuestionViewController.php index 655e77f..bcb076b 100755 --- a/src/Controller/QuestionViewController.php +++ b/src/Controller/QuestionViewController.php @@ -2,6 +2,7 @@ namespace Drupal\asklib\Controller; +use Drupal\asklib\Entity\Question; use Exception; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Controller\EntityViewController; @@ -27,13 +28,19 @@ public function renderEmail(QuestionInterface $asklib_question) { $langcode = $asklib_question->language()->getId(); $recipient = $asklib_question->getEmail(); - $data = [ + // Set the question "answered" for preview. + $asklib_question->setState(Question::STATE_ANSWERED); + + $mail = [ 'from' => \Drupal::currentUser(), 'asklib_question' => $asklib_question, 'files' => $asklib_question->getAnswer()->getAttachments(), + 'do_not_send' => true, // This will cancel the mailing in 'asklib_mailer_post_render'. ]; - $mail = \Drupal::service('plugin.manager.mail')->mail('asklib', 'answer', $recipient, $langcode, $data, null, false); + $reply_to = $asklib_question->getAnsweredBy(); + + $mail = \Drupal::service('plugin.manager.mail')->mail('asklib', 'answer', $recipient, $langcode, $mail, $reply_to); return new Response($mail['body']); } diff --git a/src/Entity/Answer.php b/src/Entity/Answer.php index c8d96f8..18c73fb 100644 --- a/src/Entity/Answer.php +++ b/src/Entity/Answer.php @@ -279,9 +279,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['created'] = BaseFieldDefinition::create('created') ->setLabel(t('Created')) ->setDescription(t('The time that the node was created.')) - ->setDisplayOptions('view', array( - 'type' => 'hidden', - )); + ->setDisplayOptions('view', ['type' => 'hidden']); $fields['changed'] = BaseFieldDefinition::create('changed') ->setLabel(t('Updated')) diff --git a/src/Entity/Lock.php b/src/Entity/Lock.php index 8b52b1e..204128f 100644 --- a/src/Entity/Lock.php +++ b/src/Entity/Lock.php @@ -55,6 +55,7 @@ public function getCreatedTime() { } public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { + $fields = []; $fields['id'] = BaseFieldDefinition::create('integer') ->setLabel(t('ID')) ->setDescription(t('Lock ID')) diff --git a/src/Entity/Question.php b/src/Entity/Question.php index 9c77e23..991baf8 100755 --- a/src/Entity/Question.php +++ b/src/Entity/Question.php @@ -2,6 +2,7 @@ namespace Drupal\asklib\Entity; +use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; use Drupal; use LogicException; use RuntimeException; @@ -105,7 +106,7 @@ public function setNotificationFlags($flags) { public function reserve($user_or_id) { $uid = is_object($user_or_id) ? $user_or_id->id() : $user_or_id; - $lock = Drupal::entityManager()->getStorage('asklib_lock')->create(); + $lock = \Drupal::service('entity_type.manager')->getStorage('asklib_lock')->create(); $lock->setUser($uid); $lock->setQuestion($this); @@ -326,7 +327,7 @@ public function setAnsweredTime($time) { throw new LogicException('Cannot set answer time without Answer object'); } if ($time instanceof DateTime) { - $time = $time->format(DATETIME_DATETIME_STORAGE_FORMAT); + $time = $time->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT); } $this->getAnswer()->setAnsweredTime($time); } @@ -562,7 +563,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setDescription(t('Municipality of the user.')) ->setSettings([ 'target_type' => 'taxonomy_term', - 'handler' => 'default', + 'handler' => 'asklib_question_municipality_selection', 'handler_settings' => [ 'target_bundles' => ['asklib_municipalities' => 'asklib_municipalities'], 'sort' => [ diff --git a/src/EventSubscriber/AllowRemoteQuestionFrames.php b/src/EventSubscriber/AllowRemoteQuestionFrames.php index 894a3c1..bb27452 100644 --- a/src/EventSubscriber/AllowRemoteQuestionFrames.php +++ b/src/EventSubscriber/AllowRemoteQuestionFrames.php @@ -2,17 +2,18 @@ namespace Drupal\asklib\EventSubscriber; +use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; class AllowRemoteQuestionFrames implements EventSubscriberInterface { public static function getSubscribedEvents() { + $events = []; $events[KernelEvents::RESPONSE] = [['onResponse']]; return $events; } - public function onResponse(FilterResponseEvent $event) { + public function onResponse(ResponseEvent $event) { $path = $event->getRequest()->getPathInfo(); if (strpos($path, '/asklib/embed/') === 0) { diff --git a/src/EventSubscriber/UserPageOverride.php b/src/EventSubscriber/UserPageOverride.php index acb477c..06bd594 100644 --- a/src/EventSubscriber/UserPageOverride.php +++ b/src/EventSubscriber/UserPageOverride.php @@ -2,12 +2,12 @@ namespace Drupal\asklib\EventSubscriber; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; class UserPageOverride implements EventSubscriberInterface { public static function getSubscribedEvents() { @@ -21,7 +21,7 @@ public function __construct(RouteMatchInterface $route_match, AccountInterface $ $this->currentUser = $current_user; } - public function onRequest(GetResponseEvent $event) { + public function onRequest(RequestEvent $event) { $allowed = $this->currentUser->hasPermission('answer questions'); if ($allowed && $this->currentRoute->getRouteName() == 'user.page') { diff --git a/src/Form/AdminForm.php b/src/Form/AdminForm.php index 60bb5bf..91a5c08 100644 --- a/src/Form/AdminForm.php +++ b/src/Form/AdminForm.php @@ -14,7 +14,7 @@ class AdminForm extends ConfigFormBase { public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), - $container->get('entity.manager')->getStorage("taxonomy_term") + $container->get('entity_type.manager')->getStorage("taxonomy_term") ); } @@ -85,7 +85,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { ]; $terms = $this->terms->loadByProperties(['vid' => 'forums']); - $options = array_map(function($term) { return $term->label(); }, $terms); + $options = array_map(fn($term) => $term->label(), $terms); $form['field_forum'] = [ '#type' => 'details', diff --git a/src/Form/MailGroupUserForm.php b/src/Form/MailGroupUserForm.php index 71cb548..ca0dc75 100644 --- a/src/Form/MailGroupUserForm.php +++ b/src/Form/MailGroupUserForm.php @@ -8,6 +8,9 @@ use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Entity\EntityRepositoryInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; +use Drupal\Component\Datetime\TimeInterface; class MailGroupUserForm extends ContentEntityForm { private $groupHelper; @@ -21,14 +24,19 @@ class MailGroupUserForm extends ContentEntityForm { public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager'), + $container->get('entity.repository'), + $container->get('entity_type.bundle.info'), + $container->get('datetime.time'), $container->get('user.data'), $container->get('asklib.user_mail_group_helper') ); } - public function __construct(EntityManagerInterface $entity_manager, UserDataInterface $config, UserMailGroupHelper $group_helper) { - parent::__construct($entity_manager); + public function __construct( + EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, + UserDataInterface $config, UserMailGroupHelper $group_helper) { + + parent::__construct($entity_repository, $entity_type_bundle_info, $time); $this->userData = $config; $this->groupHelper = $group_helper; } @@ -39,7 +47,7 @@ public function form(array $form, FormStateInterface $form_state) { $user_groups = $this->groupHelper->getGroupsForUser($this->entity->id()); $groups = $this->sortGroups($this->groups(), $user_groups); - $labels = array_map(function($term) { return $term->label(); }, $groups); + $labels = array_map(fn($term) => $term->label(), $groups); if (empty($form['field_asklib_mail']['widget'][0]['value']['#default_value'])) { $form['field_asklib_mail']['widget'][0]['value']['#default_value'] = $this->entity->getEmail(); @@ -50,7 +58,7 @@ public function form(array $form, FormStateInterface $form_state) { $form['field_asklib_signature']['widget'][0]['value']['#default_value'] = $this->getSetting('email.signature'); } - $label_suffix = array_map(function($g) { return $g->getName(); }, $user_groups); + $label_suffix = array_map(fn($g) => $g->getName(), $user_groups); $label_suffix = implode(', ', $label_suffix); if ($label_suffix) { @@ -82,8 +90,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } private function groups() { - $storage = $this->entityManager->getStorage('taxonomy_term'); + $storage = $this->entityTypeManager->getStorage('taxonomy_term'); $tids = $storage->getQuery() + ->accessCheck(false) ->sort('tid') ->condition('vid', ['asklib_libraries', 'asklib_municipalities'], 'in') ->execute(); diff --git a/src/Form/MailingGroupsForm.php b/src/Form/MailingGroupsForm.php index 1f0626b..8796969 100644 --- a/src/Form/MailingGroupsForm.php +++ b/src/Form/MailingGroupsForm.php @@ -14,7 +14,7 @@ public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), - $container->get('entity.manager')->getStorage('taxonomy_term') + $container->get('entity_type.manager')->getStorage('taxonomy_term') ); } @@ -30,6 +30,7 @@ public function getFormId() public function buildForm(array $form, FormStateInterface $form_state) { + $mopts = []; $config = $this->config('asklib.settings'); $form = parent::buildForm($form, $form_state); diff --git a/src/Form/ProvideEntityFormActionGetter.php b/src/Form/ProvideEntityFormActionGetter.php index 9887779..370f62f 100644 --- a/src/Form/ProvideEntityFormActionGetter.php +++ b/src/Form/ProvideEntityFormActionGetter.php @@ -9,7 +9,7 @@ */ trait ProvideEntityFormActionGetter { public function action($id) { - return $this->entityManager->getStorage('action')->load($id); + return $this->entityTypeManager->getStorage('action')->load($id); } public function executeAction($action_id, QuestionInterface $question) { diff --git a/src/Form/QuestionAdminForm.php b/src/Form/QuestionAdminForm.php index 0f52fe1..0f588e0 100644 --- a/src/Form/QuestionAdminForm.php +++ b/src/Form/QuestionAdminForm.php @@ -8,7 +8,7 @@ use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Path\AliasStorageInterface; +use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Render\Element; use Drupal\Core\Url; use Drupal\asklib\ProvideQuestionFormHeader; @@ -18,8 +18,11 @@ use Drupal\autoslug\SluggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; +use Drupal\Component\Datetime\TimeInterface; use Drupal\Core\Config\Config; +use Drupal\Core\Entity\EntityRepositoryInterface; class QuestionAdminForm extends ContentEntityForm { use ProvideEntityFormActionGetter; @@ -32,17 +35,23 @@ class QuestionAdminForm extends ContentEntityForm { public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager'), + $container->get('entity.repository'), + $container->get('entity_type.bundle.info'), + $container->get('datetime.time'), $container->get('date.formatter'), - $container->get('path.alias_storage'), + $container->get('entity_type.manager')->getStorage('path_alias'), $container->get('autoslug.slugger.default'), $container->get('config.factory')->get('asklib.settings'), $container->get('asklib.user_mail_group_helper') ); } - public function __construct(EntityManagerInterface $em, DateFormatterInterface $dates, AliasStorageInterface $aliases, SluggerInterface $alias_generator, Config $config, UserMailGroupHelper $mail_groups) { - parent::__construct($em); + public function __construct( + EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, + DateFormatterInterface $dates, EntityStorageInterface $aliases, SluggerInterface $alias_generator, Config $config, UserMailGroupHelper $mail_groups + ) { + + parent::__construct($entity_repository, $entity_type_bundle_info, $time); $this->dates = $dates; $this->aliases = $aliases; $this->aliasGenerator = $alias_generator; @@ -55,7 +64,7 @@ public function form(array $form, FormStateInterface $form_state) { $answer = $question->getAnswer(); if (!$answer && $question->isReservedTo($this->currentUser())) { - $answer = $this->entityManager->getStorage('asklib_answer')->create(); + $answer = $this->entityTypeManager->getStorage('asklib_answer')->create(); $question->setAnswer($answer); } @@ -151,7 +160,7 @@ public function form(array $form, FormStateInterface $form_state) { '#type' => 'link', '#weight' => 100, '#title' => $this->t('Redirect to another group'), - '#url' => $question->urlInfo('redirect-form'), + '#url' => $question->toUrl('redirect-form'), '#access' => $question->isAvailableTo($this->currentUser()) && !$question->isAnswered(), ] ]; @@ -238,7 +247,17 @@ public function form(array $form, FormStateInterface $form_state) { $form['tags']['#group'] = 'tags_group'; $form['tags']['#attached']['library'][] = 'finto_taxonomy/kifiform-tags-plugin'; - $form['tags']['widget']['target_id']['#description'] = $this->t('Select keywords from the drop-down list or press Enter to add a new one.'); + // Add this block to restrict new term creation in 'asklib_tags' when language is Swedish or English + $content_langcode = $this->entity->language()->getId(); + if (in_array($content_langcode, ['sv', 'en'])) { + // Allow auto creation only in 'finto' vocabulary. + $form['tags']['widget']['#selection_settings']['auto_create_bundles'] = ['finto']; + $form['#attached']['drupalSettings']['kifiform'] = [ + 'disableEnter' => TRUE, + ]; + } + + $form['tags']['widget']['target_id']['#description'] = $this->t('Select keywords from the drop-down list.'); $form['tags']['tags_legend'] = [ 'finto_legend' => [ @@ -394,6 +413,7 @@ public function form(array $form, FormStateInterface $form_state) { // Add header after possibly disabling inputs. $form['header'] = $this->getQuestionFormHeader($question); + // dump($form['tags']); return $form; } @@ -416,20 +436,6 @@ public function actions(array $form, FormStateInterface $form_state) { '#limit_validation_errors' => [], ]; } else if ($question->access('release')) { - $actions['release'] = [ - '#type' => 'submit', - // '#value' => $this->t('Release question'), - '#value' => $question->isAnswered() ? $this->t('Release question') : $this->t('Release to waiting queue'), - '#submit' => ['::release'], - '#validate' => ['::validateRelease'], - '#limit_validation_errors' => [], - - // This button is placed in the reserved status notification and we want to hide it - // from the bottom of the form. - '#attributes' => [ - 'style' => 'display: none' - ] - ]; $actions['submit']['#submit'] = [ '::submitForm', @@ -472,7 +478,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } else { $answer_data['email_sent'] = NULL; - $answer = $this->entityManager->getStorage('asklib_answer')->create($answer_data); + $answer = $this->entityTypeManager->getStorage('asklib_answer')->create($answer_data); $answer->setUser($this->currentUser()->id()); $this->entity->setAnswer($answer); } @@ -486,9 +492,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $old_langcode = $term->language()->getId(); $new_langcode = $this->entity->language()->getId(); - $new_term = $this->entityManager->getStorage('taxonomy_term')->create([ + $new_term = $this->entityTypeManager->getStorage('taxonomy_term')->create([ 'name' => $term->getName(), - 'vid' => $term->getVocabularyId(), + 'vid' => $term->bundle(), 'langcode' => $new_langcode, ]); @@ -504,7 +510,7 @@ public function save(array $form, FormStateInterface $form_state) { $answer->save(); } - drupal_set_message(t('Changes have been saved.')); + $this->messenger()->addStatus(t('Changes have been saved.')); return $status; } @@ -515,20 +521,20 @@ public function processMarkAnswered(array $form, FormStateInterface $form_state) if ($skip_email && !$question->isAnswered()) { $this->executeAction('asklib_mark_question_answered', $question); - drupal_set_message(t('Question was marked answered.')); + $this->messenger()->addStatus(t('Question was marked answered.')); $form_state->setRedirect('view.asklib_index.page_1'); } else if (!$skip_email && !$question->getEmailSentTime() && $question->isAnswered()) { $question->getAnswer()->setAnsweredTime(NULL); - drupal_set_message(t('Question was marked unanswered.')); + $this->messenger()->addStatus(t('Question was marked unanswered.')); } } public function processSlug(array $form, FormStateInterface $form_state) { $langcode = $this->entity->language()->getId(); - $source = '/' . $this->entity->urlInfo()->getInternalPath(); - $match = $this->aliases->load([ - 'source' => $source, + $source = '/' . $this->entity->toUrl()->getInternalPath(); + $path_alias = $this->aliases->loadByProperties([ + 'path' => $source, 'langcode' => $langcode, ]); @@ -538,8 +544,18 @@ public function processSlug(array $form, FormStateInterface $form_state) { $alias = substr_replace($alias, $slug, strrpos($alias, '/') + 1); } - $pid = empty($match) ? NULL : $match['pid']; - $this->aliases->save($source, $alias, $langcode, $pid); + if (empty($path_alias)) { + $path_alias = \Drupal::entityTypeManager()->getStorage('path_alias')->create([ + 'path' => $source, + 'alias' => $alias, + 'langcode' => $langcode + ]); + } else { + // First element is the only one we need. + $path_alias = reset($path_alias); + $path_alias->setAlias($alias); + $path_alias->save(); + } } public function validateReserve(array $form, FormStateInterface $form_state) { @@ -581,7 +597,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) { } public function redirectToPreview(array $form, FormStateInterface $form_state) { - $form_state->setRedirectUrl($this->entity->urlInfo('email-form')); + $form_state->setRedirectUrl($this->entity->toUrl('email-form')); } public function reserve(array $form, FormStateInterface $form_state) { @@ -599,7 +615,7 @@ public function release(array $form, FormStateInterface $form_state) { $question->release()->save(); $form_state->setRedirect('view.asklib_index.page_1'); - drupal_set_message(t('Question released successfully.')); + $this->messenger()->addStatus(t('Question released successfully.')); } protected function rowCountForQuestion($body, $fallback = 4) { @@ -610,11 +626,11 @@ protected function rowCountForQuestion($body, $fallback = 4) { } protected function slugForQuestion() { - $slug = substr(strrchr($this->entity->url(), '/'), 1); + $slug = substr(strrchr($this->entity->toUrl()->toString(), '/'), 1); if (!ctype_digit($slug)) { // Strip query variables potentially injected by other modules etc. - list($slug, $_) = explode('?', $slug . '?'); + [$slug, $_] = explode('?', $slug . '?'); return $slug; } @@ -646,7 +662,7 @@ protected function getQuestionFormHeader(QuestionInterface $question) { 'class' => ['messages', 'messages--error'], ], '#value' => $this->t('This question is reserved to user @user until @date. You can only view this question.', [ - '@user' => $lock->getUser()->getUsername(), + '@user' => $lock->getUser()->getDisplayName(), '@date' => $this->dates->format($expires, 'month_and_day'), ]), ]; @@ -664,13 +680,19 @@ protected function getQuestionFormHeader(QuestionInterface $question) { } if ($question->access('release')) { - $header['release'] = [ - '#type' => 'button', - '#value' => $question->isAnswered() ? $this->t('Release question') : $this->t('Release to waiting queue'), - '#attributes' => [ - 'formnovalidate' => true, - ], - ]; + $header['release'] = [ + '#type' => 'submit', + '#value' => $question->isAnswered() + ? $this->t('Release question') + : $this->t('Release to waiting queue'), + '#name' => 'question_release_header', + '#submit' => ['::release'], + '#validate' => ['::validateRelease'], + '#limit_validation_errors' => [], + '#attributes' => [ + 'formnovalidate' => 'formnovalidate', + ], + ]; } } else { $header['reserved_status'] = [ @@ -686,10 +708,11 @@ protected function getQuestionFormHeader(QuestionInterface $question) { } protected function buildQuestionLockHistory() { - $storage = $this->entityManager->getStorage('asklib_lock'); + $storage = $this->entityTypeManager->getStorage('asklib_lock'); $lids = $storage->getQuery() ->condition('question', $this->entity->id()) ->sort('created', 'DESC') + ->accessCheck(false) ->execute(); $locks = $storage->loadMultiple($lids); @@ -702,12 +725,13 @@ protected function buildQuestionLockHistory() { ]; foreach ($locks as $lock) { + $table['#rows'][] = [ [ 'data' => [ '#type' => 'link', - '#title' => $lock->getUser()->getUsername(), - '#url' => $lock->getUser()->urlInfo(), + '#title' => $lock->getUser()->getAccountName(), + '#url' => $lock->getUser()->toUrl(), ] ], [ diff --git a/src/Form/QuestionChannelForm.php b/src/Form/QuestionChannelForm.php index 1766c39..04007b6 100644 --- a/src/Form/QuestionChannelForm.php +++ b/src/Form/QuestionChannelForm.php @@ -25,12 +25,12 @@ public function form(array $form, FormStateInterface $form_state) { public function save(array $form, FormStateInterface $form_state) { $status = parent::save($form, $form_state); - $form_state->setRedirectUrl($this->entity->urlInfo('collection')); + $form_state->setRedirectUrl($this->entity->toUrl('collection')); if ($status == SAVED_NEW) { - drupal_set_message($this->t('Channel @id has been created.', ['@id' => $this->entity->id()])); + $this->messenger()->addStatus($this->t('Channel @id has been created.', ['@id' => $this->entity->id()])); } else { - drupal_set_message($this->t('Changes have been saved.')); + $this->messenger()->addStatus($this->t('Changes have been saved.')); } return $status; diff --git a/src/Form/QuestionDeleteForm.php b/src/Form/QuestionDeleteForm.php index 6812190..e925691 100644 --- a/src/Form/QuestionDeleteForm.php +++ b/src/Form/QuestionDeleteForm.php @@ -31,7 +31,7 @@ public function getDescription() public function submitForm(array &$form, FormStateInterface $form_state) { $this->entity->delete(); - drupal_set_message($this->t('The question has been deleted.')); + $this->messenger()->addStatus($this->t('The question has been deleted.')); $this->logger('content')->notice('Deleted question @id', ['@id' => $this->entity->id()]); $form_state->setRedirectUrl($this->getCancelUrl()); } diff --git a/src/Form/QuestionEmailPreviewForm.php b/src/Form/QuestionEmailPreviewForm.php index e40c67d..759dfce 100644 --- a/src/Form/QuestionEmailPreviewForm.php +++ b/src/Form/QuestionEmailPreviewForm.php @@ -6,7 +6,6 @@ use Drupal\Component\Utility\Html; use Drupal\Core\Url; use Drupal\Core\Entity\ContentEntityForm; -use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; use Drupal\File\FileUsage\FileUsageInterface; @@ -14,6 +13,9 @@ use Drupal\asklib\UserMailGroupHelper; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Drupal\Core\Entity\EntityRepositoryInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; +use Drupal\Component\Datetime\TimeInterface; use Drupal\Core\Session\AccountInterface; @@ -24,13 +26,18 @@ class QuestionEmailPreviewForm extends ContentEntityForm { public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager'), + $container->get('entity.repository'), + $container->get('entity_type.bundle.info'), + $container->get('datetime.time'), $container->get('asklib.user_mail_group_helper') ); } - public function __construct(EntityManagerInterface $em, UserMailGroupHelper $mail_groups) { - parent::__construct($em); + public function __construct( + EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, + UserMailGroupHelper $mail_groups + ) { + parent::__construct($entity_repository, $entity_type_bundle_info, $time); $this->mailGroups = $mail_groups; } @@ -40,7 +47,7 @@ public function form(array $form, FormStateInterface $form_state) { $question = $this->entity; $answer = $question->getAnswer(); - $sender = $this->entityManager->getStorage('user')->load($this->currentUser()->id()); + $sender = $this->entityTypeManager->getStorage('user')->load($this->currentUser()->id()); foreach (Element::children($form) as $name) { $form[$name]['#access'] = FALSE; @@ -126,7 +133,7 @@ public function form(array $form, FormStateInterface $form_state) { '#tag' => 'iframe', '#attributes' => [ 'class' => ['email-preview-frame'], - 'src' => $question->urlInfo('email-preview')->toString(), + 'src' => $question->toUrl('email-preview')->toString(), 'style' => 'width: 100%; min-height: 400px;', ], ]; @@ -205,7 +212,7 @@ public function sendEmail(array $form, FormStateInterface $form_state) { $this->executeAction('asklib_mark_question_answered', $this->entity); $form_state->setRedirect('view.asklib_index.page_1'); - drupal_set_message(t('Email was sent successfully.')); + $this->messenger()->addStatus(t('Email was sent successfully.')); } public function save(array $form, FormStateInterface $form_state) { diff --git a/src/Form/QuestionForm.php b/src/Form/QuestionForm.php index 89ca830..86bebf2 100755 --- a/src/Form/QuestionForm.php +++ b/src/Form/QuestionForm.php @@ -92,8 +92,9 @@ public function actions(array $form, FormStateInterface $form_state) { public function processTheme(array $form, FormStateInterface $form_state) { if ($tid = $form_state->getValue('theme')) { - $term_storage = $this->entityManager->getStorage('taxonomy_term'); + $term_storage = $this->entityTypeManager->getStorage('taxonomy_term'); $query = $term_storage->getQuery() + ->accessCheck(FALSE) ->condition('vid', 'asklib_libraries') ->condition('field_asklib_theme', $tid); @@ -116,7 +117,7 @@ public function submitForm(array & $form, FormStateInterface $form_state) { public function save(array $form, FormStateInterface $form_state) { $this->entity->setNotificationFlags(-1); - drupal_set_message(t('Thank you for your question! We will answer you within three days. If you do not hear from us, please contact us at @email.', [ + $this->messenger()->addStatus(t('Thank you for your question! We will answer you within three days. If you do not hear from us, please contact us at @email.', [ '@email' => 'toimitus@kirjastot.fi' ])); @@ -130,6 +131,7 @@ protected function getCategoryOptions() { ->select('taxonomy_term_field_data', 't') ->fields('t', ['tid', 'name']) ->condition('t.vid', 'asklib_themes') + ->condition('t.status', 1) ->condition('t.langcode', $langcode) ->orderBy('t.name') ; diff --git a/src/Form/QuestionRedirectForm.php b/src/Form/QuestionRedirectForm.php index f7b54e7..8d2c558 100644 --- a/src/Form/QuestionRedirectForm.php +++ b/src/Form/QuestionRedirectForm.php @@ -33,7 +33,7 @@ public function form(array $form, FormStateInterface $form_state) { } protected function filterDisabledAnswerers(array $options) { - $storage = $this->entityManager->getStorage('taxonomy_term'); + $storage = $this->entityTypeManager->getStorage('taxonomy_term'); foreach ($options as $id => $item) { if (is_array($item)) { @@ -60,7 +60,7 @@ public function actions(array $form, FormStateInterface $form_state) { public function save(array $form, FormStateInterface $form_state) { $this->entity->setNotificationFlags(QuestionInterface::NOTIFY_SUBSCRIBERS); $form_state->setRedirect('view.asklib_index.page_1'); - drupal_set_message(t('Target library updated.')); + $this->messenger()->addStatus(t('Target library updated.')); return parent::save($form, $form_state); } diff --git a/src/Form/RemoteQuestionForm.php b/src/Form/RemoteQuestionForm.php index a6e0346..eb4a947 100644 --- a/src/Form/RemoteQuestionForm.php +++ b/src/Form/RemoteQuestionForm.php @@ -28,6 +28,14 @@ public function form(array $form, FormStateInterface $form_state) { } } + // Check if form was submitted by looking for the URL query parameter. + $submitted = \Drupal::request()->query->get('submitted'); + + if ($submitted) { + $message = \Drupal::config('asklib.settings')->get('confirmation'); + $this->messenger()->addStatus($message); + } + // Need to set language manually because Question is not marked as 'translatable'. $form['langcode'] = [ '#type' => 'value', @@ -62,8 +70,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) { public function save(array $form, FormStateInterface $form_state) { $this->entity->setNotificationFlags(-1); - $message = \Drupal::config('asklib.settings')->get('confirmation'); - drupal_set_message($message); + $current_path = \Drupal::service('path.current')->getPath(); + $form_state->setRedirectUrl(\Drupal\Core\Url::fromUserInput($current_path, ['query' => ['submitted' => 1]])); return parent::save($form, $form_state); } @@ -71,7 +79,7 @@ public function save(array $form, FormStateInterface $form_state) { private function channelFromRoute() { $term = \Drupal::routeMatch()->getParameter('channel'); - if ($term->getVocabularyId() != 'asklib_channels') { + if ($term->bundle() != 'asklib_channels') { throw new NotFoundHttpException; } diff --git a/src/Form/RespondentsForm.php b/src/Form/RespondentsForm.php index 038cab4..1fbcdb5 100644 --- a/src/Form/RespondentsForm.php +++ b/src/Form/RespondentsForm.php @@ -12,7 +12,7 @@ class RespondentsForm extends ConfigFormBase { public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), - $container->get('entity.manager')->getStorage('taxonomy_term') + $container->get('entity_type.manager')->getStorage('taxonomy_term') ); } @@ -26,6 +26,7 @@ public function getFormId() { } public function buildForm(array $form, FormStateInterface $form_state) { + $mopts = []; $config = $this->config('asklib.settings'); $form = parent::buildForm($form, $form_state); diff --git a/src/Form/UserMailingGroupsForm.php b/src/Form/UserMailingGroupsForm.php index ed1c07d..751d850 100644 --- a/src/Form/UserMailingGroupsForm.php +++ b/src/Form/UserMailingGroupsForm.php @@ -15,7 +15,7 @@ class UserMailingGroupsForm extends ConfigFormBase { public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), - $container->get('entity.manager')->getStorage('user') + $container->get('entity_type.manager')->getStorage('user') ); } @@ -29,6 +29,7 @@ public function getFormId() { } public function buildForm(array $form, FormStateInterface $form_state) { + $mopts = []; $config = $this->config('asklib.settings'); $form = parent::buildForm($form, $form_state); diff --git a/src/MailGroupListBuilder.php b/src/MailGroupListBuilder.php index ed5ab55..8d90cb7 100644 --- a/src/MailGroupListBuilder.php +++ b/src/MailGroupListBuilder.php @@ -30,6 +30,7 @@ public function buildHeader() { } public function buildRow(EntityInterface $term) { + $row = []; $status = [ $this->t('Disabled'), $this->t('Enabled'), @@ -37,7 +38,7 @@ public function buildRow(EntityInterface $term) { $row['name']['data'] = [ '#type' => 'link', '#title' => $term->label(), - '#url' => $term->urlInfo(), + '#url' => $term->toUrl(), ]; $row['type'] = $term->vid->entity->label(); $row['enabled'] = $status[$term->get('field_asklib_active')->value]; @@ -49,7 +50,7 @@ protected function getDefaultOperations(EntityInterface $term) { $ops['edit'] = [ 'title' => $this->t('Edit'), - 'url' => $term->urlInfo('asklib-mail-group-form'), + 'url' => $term->toUrl('asklib-mail-group-form'), 'weight' => 0, ]; @@ -71,6 +72,6 @@ protected function getEntityIds() { $query->pager($this->limit); } - return $query->execute(); + return $query->accessCheck(FALSE)->execute(); } } diff --git a/src/MailUserListBuilder.php b/src/MailUserListBuilder.php index 88b6593..a56ef21 100644 --- a/src/MailUserListBuilder.php +++ b/src/MailUserListBuilder.php @@ -32,6 +32,7 @@ public function buildHeader() public function buildRow(EntityInterface $user) { + $row = []; $groups = []; foreach ($this->groups($user->id()) as $tid) { $groups[] = $this->term_cache[$tid]->label(); @@ -67,7 +68,7 @@ protected function getEntityIds() { $query->pager($this->limit); } - return $query->execute(); + return $query->accessCheck(FALSE)->execute(); } protected function getDefaultOperations(EntityInterface $term) { @@ -75,7 +76,7 @@ protected function getDefaultOperations(EntityInterface $term) { $ops['edit'] = [ 'title' => $this->t('Edit'), - 'url' => $term->urlInfo('asklib-mail-group-form'), + 'url' => $term->toUrl('asklib-mail-group-form'), 'weight' => 0, ]; @@ -90,13 +91,13 @@ private function cacheGroups($uids) { if (empty($uids)) { return; } - $phs = implode(',', array_fill(0, count($uids), '?')); + $phs = implode(',', array_fill(0, is_countable($uids) ? count($uids) : 0, '?')); $query = sprintf(' SELECT entity_id tid, field_asklib_subscribers_target_id uid FROM {taxonomy_term__field_asklib_subscribers} WHERE field_asklib_subscribers_target_id IN (%s) ', $phs); - $smt = \Drupal::service('database')->prepareQuery($query); + $smt = \Drupal::service('database')->prepareStatement($query, ['allow_square_brackets' => FALSE]); $smt->execute(array_values($uids)); $tids = []; @@ -106,6 +107,6 @@ private function cacheGroups($uids) { $tids[] = $row->tid; } - $this->term_cache = \Drupal::entityManager()->getStorage('taxonomy_term')->loadMultiple($tids); + $this->term_cache = \Drupal::service('entity_type.manager')->getStorage('taxonomy_term')->loadMultiple($tids); } } diff --git a/src/Plugin/Action/EmailActionBase.php b/src/Plugin/Action/EmailActionBase.php index f5b75f8..25afe9f 100644 --- a/src/Plugin/Action/EmailActionBase.php +++ b/src/Plugin/Action/EmailActionBase.php @@ -42,9 +42,6 @@ public function access($object, AccountInterface $account = NULL, $return_as_obj } protected function mail($mail_id, $recipients, $langcode, $mail, $reply_to = null) { - if (is_array($recipients)) { - $recipients = implode(', ', $recipients); - } if (is_null($reply_to)) { $reply_to = $this->getGenericSenderAddress(); @@ -53,16 +50,30 @@ protected function mail($mail_id, $recipients, $langcode, $mail, $reply_to = nul $mail = $this->mailer->mail('asklib', $mail_id, $recipients, $langcode, $mail, $reply_to); if ($mail['result']) { - $storage = \Drupal::entityTypeManager()->getStorage('kifimail_log'); - $storage->create([ - 'module' => $mail['module'], - 'message_id' => $mail['key'], - 'email' => $mail['to'], - 'langcode' => $mail['langcode'], - 'subject' => $mail['subject'], - 'body' => $mail['body'], - 'user' => \Drupal::currentUser()->id(), - ])->save(); + + $log_message = <<notice($log_message, [ + '@module' => $mail['module'], + '@message_id' => $mail['key'], + '@email' => $mail['to'], + '@langcode' => $mail['langcode'], + '@subject' => $mail['subject'], + '@body' => $mail['body'], + '@user' => \Drupal::currentUser()->id(), + ]); + + } } @@ -71,6 +82,6 @@ protected function getGenericSenderAddress() { $site_config = $this->config->get('system.site'); $name = $config->get('reply.name'); $email = $config->get('reply.address') ?: $site_config->get('mail'); - return $name ? sprintf('%s <%s>', $name, $email) : $email; + return ['name' => $name, 'email' => $email]; } } diff --git a/src/Plugin/Action/SendAnswerEmail.php b/src/Plugin/Action/SendAnswerEmail.php index 3010d9b..f8487d8 100644 --- a/src/Plugin/Action/SendAnswerEmail.php +++ b/src/Plugin/Action/SendAnswerEmail.php @@ -23,9 +23,7 @@ public function execute($question = NULL) { 'files' => $question->getAnswer()->getAttachments() ]; - $sender = $question->getAnsweredBy(); - $sender_email = $sender->get('field_asklib_mail')->value ?: $sender->getEmail(); - $reply_to = sprintf('%s <%s>', $sender->field_real_name->value, $sender_email); + $reply_to = $question->getAnsweredBy(); $this->mail('answer', $question->getEmail(), $question->language()->getId(), $mail, $reply_to); diff --git a/src/Plugin/Action/SendClientReceiptEmail.php b/src/Plugin/Action/SendClientReceiptEmail.php index d6750a2..3e31f23 100644 --- a/src/Plugin/Action/SendClientReceiptEmail.php +++ b/src/Plugin/Action/SendClientReceiptEmail.php @@ -17,7 +17,7 @@ class SendClientReceiptEmail extends EmailActionBase { */ public function execute($question = NULL) { if ($question->getEmail()) { - $mail = ['asklib_question' => $question]; + $mail = ['asklib_question' => $question, 'files' => $question->getAttachments()]; $this->mail('new_question', $question->getEmail(), $question->language()->getId(), $mail, $this->getGenericSenderAddress()); } } diff --git a/src/Plugin/Action/SendQuestionNotifyEmail.php b/src/Plugin/Action/SendQuestionNotifyEmail.php index 7a1a370..1d90f47 100644 --- a/src/Plugin/Action/SendQuestionNotifyEmail.php +++ b/src/Plugin/Action/SendQuestionNotifyEmail.php @@ -37,8 +37,8 @@ public function execute($question = NULL) { $recipients = array_merge($recipients, $this->getGroupRecipients($city)); } - if ($recipients = array_unique($recipients)) { - $mail = ['asklib_question' => $question]; + if (is_array($recipients) && empty($recipients) === false) { + $mail = ['asklib_question' => $question, 'files' => $question->getAttachments()]; $langcode = $question->language()->getId(); $this->mail('new_question_admin', $recipients, $langcode, $mail); } @@ -61,15 +61,16 @@ protected function getGroupRecipients(TermInterface $group) { $recipients = []; if ($group->hasField('field_asklib_email') && $group->field_asklib_email->value) { - $recipients[] = sprintf('%s <%s>', $group->label(), $group->field_asklib_email->value); + $email = $group->field_asklib_email->value; + $recipients[$email] = ['name' => $group->label(), 'email' => $email]; } foreach ($users as $user) { $email = $user->get('field_asklib_mail')->value ?: $user->getEmail(); if ($user->hasField('field_real_name') && $name = $user->get('field_real_name')->value) { - $recipients[] = sprintf('%s <%s>', $name, $email); + $recipients[$email] = ['name' => $name, 'email' => $email]; } else { - $recipients[] = $email; + $recipients[$email] = ['name' => NULL, 'email' => $email]; } } return $recipients; diff --git a/src/Plugin/Block/NewForumMessages.php b/src/Plugin/Block/NewForumMessages.php index bc519f1..73585ec 100644 --- a/src/Plugin/Block/NewForumMessages.php +++ b/src/Plugin/Block/NewForumMessages.php @@ -61,8 +61,8 @@ public function build() { $basedir = \Drupal::moduleHandler()->getModule('asklib')->getPath(); foreach ($this->content() as $delta => $item) { - $user_url = $this->userStorage->create(['uid' => $item->user->id])->urlInfo(); - $post_url = $this->nodeStorage->create(['nid' => $item->nid, 'type' => 'forum'])->urlInfo(); + $user_url = $this->userStorage->create(['uid' => $item->user->id])->toUrl(); + $post_url = $this->nodeStorage->create(['nid' => $item->nid, 'type' => 'forum'])->toUrl(); if ($item->type == 'comment') { $icon = 'icon-comment.svg'; @@ -160,7 +160,7 @@ protected function content() { } protected function newTopics() { - $query = db_select('forum_index', 'f') + $query = \Drupal::database()->select('forum_index', 'f') ->fields('f') ->fields('b', ['body_value', 'body_format']) ->fields('n', ['langcode']) @@ -201,7 +201,7 @@ protected function newTopics() { } protected function newComments() { - $query = db_select('comment_field_data', 'c') + $query = \Drupal::database()->select('comment_field_data', 'c') ->fields('c') ->fields('b', ['comment_body_value', 'comment_body_format']) ->fields('f', ['title']) @@ -248,9 +248,7 @@ protected function forum() { protected function mergeItems(array $topics, array $comments) { $items = array_merge($topics, $comments); - usort($items, function($a, $b) { - return $b->created - $a->created; - }); + usort($items, fn($a, $b) => $b->created - $a->created); return array_slice($items, 0, $this->configuration['block_count']); } diff --git a/src/Plugin/Block/SimilarQuestions.php b/src/Plugin/Block/SimilarQuestions.php index 79561b9..c34b493 100644 --- a/src/Plugin/Block/SimilarQuestions.php +++ b/src/Plugin/Block/SimilarQuestions.php @@ -54,7 +54,7 @@ public function build() { 'link' => [ '#type' => 'link', '#title' => $question->label(), - '#url' => $question->urlInfo(), + '#url' => $question->toUrl(), ] ]; } diff --git a/src/Plugin/EmailBuilder/AskLibEmailBuilder.php b/src/Plugin/EmailBuilder/AskLibEmailBuilder.php new file mode 100644 index 0000000..bc0103a --- /dev/null +++ b/src/Plugin/EmailBuilder/AskLibEmailBuilder.php @@ -0,0 +1,154 @@ +setParam('langcode', $langcode); + + $email->setParam('asklib_question', $question); + $email->setVariable('asklib_question', $question); + + if($question->isAnswered()) + { + $email->setParam('asklib_answer', $question->getAnswer()); + $email->setVariable('asklib_answer', $question->getAnswer()); + + $email->setVariable('has_answer_details', !empty($question->getAnswer()->getDetails())); + } + + $email->setParam('recipients', $recipients); + $email->setParam('reply-to', $reply_to); + $email->setParam('from', $from); + $email->setParam('attachments', $attachments); + $email->setParam('do_not_send', $do_not_send); + + + $email->setVariable('is_admin', \Drupal::currentUser()->hasPermission('administer asklib')); + $email->setVariable('has_question_details', !empty($question->getDetails())); + } + + public function fromArray(EmailFactoryInterface $factory, array $message) { + + $recipients = $message['to']; + $reply_to = $message['reply-to']; + $from = NULL; + if(!empty($message['params']['from'])) + { + $from = $message['params']['from']->getEmail(); + } + + $attachments = []; + + if (isset($message['params']['files']) && is_array($message['params']['files']) && !empty($message['params']['files'])) + { + $attachments = $message['params']['files']; + } + + $do_not_send = (isset($message['params']['do_not_send'])) ? $message['params']['do_not_send'] : false; + + return $factory->newTypedEmail($message['module'], $message['key'], + $message['langcode'], $message['params']['asklib_question'], $recipients, $reply_to, $from, $attachments, $do_not_send); + } + + + /** + * {@inheritdoc} + */ + public function preRender(EmailInterface $email) { + $this->tokenOptions(['clear' => TRUE]); + } + + public function build(EmailInterface $email) { + + $recipients = $email->getParam('recipients'); + $question = $email->getParam('asklib_question'); + + if(is_string($recipients)) + { + $email->setTo(new Address($recipients)); + } else if(is_array($recipients)) + { + $addresses = []; + foreach($recipients as $recipient) + { + $addresses[] = new Address($recipient['email'], $recipient['name'] ?? NULL); + } + $email->setTo($addresses); + } + + $reply_to = $email->getParam('reply-to'); + if(!empty($reply_to)) + { + if(is_string($reply_to)) + { + $email->setReplyTo(new Address($reply_to)); + } + else if(is_array($reply_to) && isset($reply_to['email'])) + { + $email->setReplyTo(new Address($reply_to['email'], $reply_to['name'] ?? NULL)); + } else { + // We are dealing with User object. Get the wanted fields from there. + $sender_email = $reply_to->get('field_asklib_mail')->value ?: $reply_to->getEmail(); + $email->setReplyTo(new Address($sender_email, $reply_to->field_real_name->value)); + } + } + + $from = $email->getParam('from'); + if(!empty($from)) + { + $email->setFrom(new Address($from)); + } + + // Check for attachments + $attachments = $email->getParam('attachments'); + if (!empty($attachments)) + { + foreach($attachments as $attachment) + { + $email->attachFromPath($attachment->getFileUri()); + } + } + + // If this is an answer, then set the answeree as reply-to mail. + if($email->getSubType() == 'answer') + { + $answer = $email->getParam('asklib_answer'); + $anwerer = $answer->getUser(); + $email->setReplyTo(new Address($anwerer->get('field_asklib_mail')->value ?: $anwerer->getEmail(), $anwerer->field_real_name->value)); + } + + } + +} \ No newline at end of file diff --git a/src/Plugin/EntityReferenceSelection/MunicipalitySelection.php b/src/Plugin/EntityReferenceSelection/MunicipalitySelection.php new file mode 100644 index 0000000..09e7dca --- /dev/null +++ b/src/Plugin/EntityReferenceSelection/MunicipalitySelection.php @@ -0,0 +1,34 @@ +condition('status', 1); + + return $query; + } + +} diff --git a/src/Plugin/Field/FieldFormatter/SlugLink.php b/src/Plugin/Field/FieldFormatter/SlugLink.php index 1928ba3..2c4ed9f 100644 --- a/src/Plugin/Field/FieldFormatter/SlugLink.php +++ b/src/Plugin/Field/FieldFormatter/SlugLink.php @@ -29,13 +29,10 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $entity = $item->getEntity(); if ($entity) { - $url = $entity->url(); - // $alias = $aliases->lookupPathAlias($url, $langcode); - $elements[$delta] = [ '#type' => 'link', '#title' => $entity->label(), - '#url' => $entity->urlInfo(), + '#url' => $entity->toUrl(), ]; } } diff --git a/src/Plugin/Field/FieldWidget/AnswerWidget.php b/src/Plugin/Field/FieldWidget/AnswerWidget.php index 4c811a6..47347eb 100644 --- a/src/Plugin/Field/FieldWidget/AnswerWidget.php +++ b/src/Plugin/Field/FieldWidget/AnswerWidget.php @@ -2,6 +2,7 @@ namespace Drupal\asklib\Plugin\Field\FieldWidget; +use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal; use Drupal\Component\Utility\Html; use Drupal\Core\Entity\Display\EntityFormDisplayInterface; @@ -37,7 +38,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen ]; } - $display = \Drupal\Core\Entity\Entity\EntityFormDisplay::collectRenderDisplay($answer, 'default'); + $display = EntityFormDisplay::collectRenderDisplay($answer, 'default'); $element['body'] = $display->getRenderer('body')->form($answer->get('body'), $form, $form_state); @@ -51,7 +52,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element['rating'] = $display->getRenderer('rating')->form($answer->get('rating'), $form, $form_state); - $fids = array_map(function($o) { return $o->id(); }, $answer->getAttachments()); + $fids = array_map(fn($o) => $o->id(), $answer->getAttachments()); $element['attachments'] = [ '#type' => 'managed_file', diff --git a/src/Plugin/Field/FieldWidget/ParentQuestion.php b/src/Plugin/Field/FieldWidget/ParentQuestion.php index 230b742..62efd33 100644 --- a/src/Plugin/Field/FieldWidget/ParentQuestion.php +++ b/src/Plugin/Field/FieldWidget/ParentQuestion.php @@ -36,7 +36,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen 'link' => [ '#type' => 'link', '#title' => $parent->label(), - '#url' => $parent->urlInfo('edit-form'), + '#url' => $parent->toUrl('edit-form'), ], 'value' => [ '#type' => 'value', diff --git a/src/Plugin/Search/QuestionSearch.php b/src/Plugin/Search/QuestionSearch.php index 3e67a49..4039012 100644 --- a/src/Plugin/Search/QuestionSearch.php +++ b/src/Plugin/Search/QuestionSearch.php @@ -21,13 +21,13 @@ use Drupal\asklib\QuestionInterface; use Drupal\search\Plugin\SearchIndexingInterface; use Drupal\search\Plugin\SearchPluginBase; -use Elasticsearch\Common\Exceptions\BadRequest400Exception; -use Elasticsearch\Common\Exceptions\NoNodesAvailableException; use Html2Text\Html2Text; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\kifisearch\Plugin\Search\ContentSearch; +use Ehann\RediSearch\Index; use Drupal\asklib\QuestionIndexer; +use Drupal\kifisearch\Plugin\Search\CustomSearchBase; +use Drupal\kifisearch\Query\KifiBuilderInterface; /** * Search and indexing for asklib_question and asklib_answer entities. @@ -37,26 +37,51 @@ * title = @Translation("Ask a Librarian") * ) */ -class QuestionSearch extends ContentSearch { - const SEARCH_ID = 'asklib_search'; +class QuestionSearch extends CustomSearchBase implements SearchIndexingInterface { + + + public const SEARCH_ID = 'asklib_search'; + + protected $database; + protected $searchSettings; + + static public function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('entity_type.manager'), + $container->get('language_manager'), + $container->get('kifisearch.client'), + $container->get('database'), + $container->get('config.factory')->get('search.settings') + ); + } + + public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_manager, LanguageManagerInterface $languages, Index $kifi_index, Connection $database, Config $search_settings) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_manager, $languages, $kifi_index); + + $this->database = $database; + $this->searchSettings = $search_settings; + } /** - * @param $result Elasticsearch response. + * @param $result Redisearch response. */ protected function prepareResults(array $result) { - $total = $result['hits']['total']; - $time = $result['took']; - $rows = $result['hits']['hits']; + + $total = $result['total']; + $rows = $result['hits']; $prepared = []; $cache = $this->loadMatchedEntities($result); - pager_default_initialize($total, 10); + \Drupal::service('pager.manager')->createPager($total, 10); - foreach ($result['hits']['hits'] as $hit) { - $entity_type = $hit['_source']['entity_type']; - $entity_id = $hit['_source']['id']; + foreach ($result['hits'] as $hit) { + $entity_type = $hit['entity_type']; + $entity_id = $hit['entity_id']; if (!isset($cache[$entity_type][$entity_id])) { user_error(sprintf('Stale search entry: %s #%d does not exist', $entity_type, $entity_id)); @@ -66,11 +91,11 @@ protected function prepareResults(array $result) { $question = $cache[$entity_type][$entity_id]; $build = [ - 'link' => $question->url('canonical', ['absolute' => TRUE, 'language' => $question->language()]), + 'link' => $question->toUrl('canonical', ['absolute' => TRUE, 'language' => $question->language()])->toString(), 'asklib_question' => $question, 'title' => $question->label(), - 'score' => $hit['_score'], - 'date' => strtotime($hit['_source']['created']), + 'score' => $hit['asklib_score'], + 'date' => $hit['created'], 'langcode' => $question->language()->getId(), 'snippet' => $this->processSnippet($hit), ]; @@ -91,100 +116,35 @@ protected function prepareResults(array $result) { public function updateIndex() { $storage = $this->entityManager->getStorage('asklib_question'); $batch_size = $this->searchSettings->get('index.cron_limit'); - $indexer = new QuestionIndexer($this->database, $storage, $this->client, [], $batch_size); + $indexer = new QuestionIndexer($this->database, $storage, $this->kifi_index, [], $batch_size); $indexer->updateIndex(); } public function indexStatus() { $storage = $this->entityManager->getStorage('asklib_question'); $batch_size = $this->searchSettings->get('index.cron_limit'); - $indexer = new QuestionIndexer($this->database, $storage, $this->client, [], $batch_size); + $indexer = new QuestionIndexer($this->database, $storage, $this->kifi_index, [], $batch_size); return $indexer->indexStatus(); } - protected function compileSearchQuery($query_string) { - /* - * Elasticsearch will throw an exception when the syntax is invalid, so we - * do a simple sanity check here. - */ - // $query_string = preg_replace('/^(AND|OR|NOT)/', '', trim($query_string)); - // $query_string = preg_replace('/(AND|OR|NOT)$/', '', trim($query_string)); - - if (empty($this->searchParameters['all_languages'])) { - $langcode = $this->languageManager->getCurrentLanguage()->getId(); - } else { - $langcode = NULL; - } - - $query = [ - 'bool' => [ - // 'must' => [], - // 'should' => [], - ] - ]; + protected function compileSearchQuery(KifiBuilderInterface &$search_query, $keywords) { - $query['bool']['must'][] = [ - 'term' => [ - 'entity_type' => 'asklib_question' - ] - ]; + parent::compileSearchQuery($search_query, $keywords); - $query['bool']['must'][] = [ - 'multi_match' => [ - 'query' => $query_string, - 'fields' => ['body', 'title', 'tags'], - ] - ]; + // Only search only from asklib questions. + $search_query->tagFilter('entity_type', ['asklib_question']); - if ($langcode) { - $query['bool']['must'][] = [ - 'term' => ['langcode' => [ - 'value' => $langcode, - ]], - ]; + // Apply ordering + if ($this->getParameter('order') == 'newest') + { + $search_query->sortBy('created', 'DESC'); } + // Apply channel/feeds filtering if (!empty($this->searchParameters['feeds'])) { - foreach (Tags::explode($this->searchParameters['feeds']) as $fid) { - $query['bool']['must'][] = [ - // Use the singular 'term' query to require every single term in the result. - 'term' => [ - 'terms' => (int)$fid - ] - ]; - } - } - - if (!empty($this->searchParameters['tags'])) { - foreach (Tags::explode($this->searchParameters['tags']) as $tid) { - $query['bool']['must'][] = [ - // Use the singular 'term' query to require every single term in the result. - 'term' => [ - 'terms' => (int)$tid - ] - ]; - } - } - - if (!empty($this->searchParameters['order'])) { - switch ($this->searchParameters['order']) { - case 'newest': - $sort = ['created' => 'desc']; - break; - } - } else { - $sort = ['_score' => 'desc']; + $search_query->tagFilter('terms', Tags::explode($this->searchParameters['feeds'])); } - return [ - 'query' => $query, - 'sort' => $sort, - 'highlight' => [ - 'fields' => ['body' => (object)[]], - 'pre_tags' => [''], - 'post_tags' => [''], - ] - ]; } public function searchFormAlter(array &$form, FormStateInterface $form_state) { @@ -214,10 +174,10 @@ public function searchFormAlter(array &$form, FormStateInterface $form_state) { '#type' => 'details', '#title' => $this->t('Advanced search'), '#open' => count(array_diff(array_keys($parameters), ['page', 'keys'])) > 1, - 'all_languages' => [ + 'anylang' => [ '#type' => 'checkbox', '#title' => $this->t('Search all languages'), - '#default_value' => !empty($parameters['all_languages']) + '#default_value' => !empty($parameters['anylang']) ], 'tags_container' => [ /* @@ -267,7 +227,7 @@ public function searchFormAlter(array &$form, FormStateInterface $form_state) { ]; if ($langcode != 'fi') { - $form['all_languages'] = $form['advanced']['all_languages']; + $form['anylang'] = $form['advanced']['anylang']; unset($form['advanced']); } } @@ -285,6 +245,11 @@ protected function getFeedOptions() { continue; } + // Skip unblished channels + if (!$term->isPublished()) { + continue; + } + $options[$term->id()] = (string)$term->label(); } @@ -295,12 +260,12 @@ protected function getFeedOptions() { public function buildSearchUrlQuery(FormStateInterface $form_state) { $query = parent::buildSearchUrlQuery($form_state); - if ($form_state->getValue('all_languages')) { - $query['all_languages'] = '1'; + if ($form_state->getValue('anylang')) { + $query['anylang'] = '1'; } if ($tags = $form_state->getValue('tags')) { - $query['tags'] = Tags::implode(array_map(function($t) { return $t['target_id']; }, $tags)); + $query['tags'] = Tags::implode(array_map(fn($t) => $t['target_id'], $tags)); } if ($feeds = array_filter($form_state->getValue('feeds', []))) { @@ -314,4 +279,12 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) { return $query; } + + public function markForReindex() { + $this->database->query('UPDATE {kifisearch_index} SET reindex = 1'); + } + + public function indexClear() { + $this->database->query('DELETE FROM {kifisearch_index}'); + } } diff --git a/src/Plugin/views/row/Rss.php b/src/Plugin/views/row/Rss.php index 36a29f6..2cc8474 100644 --- a/src/Plugin/views/row/Rss.php +++ b/src/Plugin/views/row/Rss.php @@ -3,7 +3,8 @@ namespace Drupal\asklib\Plugin\views\row; use stdClass; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityDisplayRepositoryInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\views\Plugin\views\row\RssPluginBase; /** @@ -21,7 +22,6 @@ */ class Rss extends RssPluginBase { public $base_table = 'asklib_questions'; - public $base_field = 'id'; // Stores the questions loaded in preRender. public $questions = []; @@ -29,6 +29,14 @@ class Rss extends RssPluginBase { protected $entityTypeId = 'asklib_question'; + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_display_repository); + $this->base_field = 'id'; + } + public function buildOptionsForm_summary_options() { $options = parent::buildOptionsForm_summary_options(); $options['title'] = $this->t('Title only'); @@ -47,14 +55,15 @@ public function preRender($values) { $qids[] = $row->{$this->field_alias}; } if (!empty($qids)) { - $this->questions = $this->entityManager->getStorage('asklib_question')->loadMultiple($qids); + $this->questions = $this->entityTypeManager->getStorage('asklib_question')->loadMultiple($qids); - $aids = $this->entityManager->getStorage('asklib_answer') + $aids = $this->entityTypeManager->getStorage('asklib_answer') ->getQuery() + ->accessCheck(TRUE) ->condition('question', $qids, 'IN') ->execute(); - $this->answers = $this->entityManager->getStorage('asklib_answer')->loadMultiple($aids); + $this->answers = $this->entityTypeManager->getStorage('asklib_answer')->loadMultiple($aids); } } @@ -75,7 +84,7 @@ public function render($row) { $answer = $question->getAnswer(); $library = $answer->getLibrary(); - $question->link = $question->url('canonical', ['absolute' => FALSE]); + $question->link = $question->toUrl('canonical', ['absolute' => FALSE]); $question->rss_namespaces = []; $question->rss_elements = [ [ @@ -93,7 +102,7 @@ public function render($row) { ] ]; - $build = entity_view($question, $display_mode, $question->language()->getId()); + $build = \Drupal::entityTypeManager()->getViewBuilder($question->getEntityTypeId())->view($question, $display_mode, $question->language()->getId()); unset($build['#theme']); if (!empty($question->rss_namespaces)) { diff --git a/src/QuestionIndexer.php b/src/QuestionIndexer.php index 04afc04..ade537a 100644 --- a/src/QuestionIndexer.php +++ b/src/QuestionIndexer.php @@ -13,6 +13,8 @@ public function getTotal() { ->condition('entity.state', QuestionInterface::STATE_ANSWERED) ->condition('entity.published', 1); + $this->excludeOldEChannelQuestions($query); + $total = $query->countQuery()->execute()->fetchField(); return $total; } @@ -24,6 +26,8 @@ public function getRemaining() { ->condition('entity.state', QuestionInterface::STATE_ANSWERED) ->condition('entity.published', 1); + $this->excludeOldEChannelQuestions($query); + // NOTE: Reindex is NULL when left join is to zero rows. $query->condition($query->orConditionGroup() ->condition('search.reindex', NULL, 'IS') @@ -95,7 +99,7 @@ public function updateIndex() { $document['tags'] = array_values(array_unique($document['tags'])); } - $document['fields']['asklib_question']['score'] = (int)$answer->getRating(); + $document['asklib_score'] = (int)$answer->getRating(); $this->index($document); } } @@ -110,6 +114,8 @@ protected function fetchItemsForIndexing() { ->condition('entity.state', QuestionInterface::STATE_ANSWERED) ->condition('entity.published', 1); + $this->excludeOldEChannelQuestions($query); + // NOTE: Reindex is NULL when left join is to zero rows. $query->condition($query->orConditionGroup() ->condition('search.reindex', NULL, 'IS') @@ -130,4 +136,35 @@ protected function fetchItemsForIndexing() { return []; } } + + protected function excludeOldEChannelQuestions(&$query) { + $echannel_id = 188298; + $echannel_cutoff_date = '23-04-2024'; + + // We need to filter out all questions, that 1. belong to the e-channel and 2. are older than 23.4. + // Unfortunately, we need to verify this in two places, 1. from 'channel' in asklib_questions, + // and 2. From table 'asklib_question__feeds'. In future, it probably would be better sync to + // either to question's channel or to the *_feeds table and then remove one of the query groups. + + + // First query based on question 'channel' parameter. + $query->condition($query->orConditionGroup() + ->condition('entity.channel', NULL, 'IS') + ->condition('entity.channel', $echannel_id, '<>') + ->condition($query->andConditionGroup() + ->condition('entity.channel', $echannel_id) + ->condition('entity.created', strtotime($echannel_cutoff_date), '>='))); + + + // Second query based on the addtional 'asklib_question__feeds' table. + $subquery = $this->database->select('asklib_questions', 'entity') + ->fields('entity', ['id']) + ->condition('entity.state', QuestionInterface::STATE_ANSWERED) + ->condition('entity.published', 1) + ->condition('entity.created', strtotime($echannel_cutoff_date), '<'); + $subquery->join('asklib_question__feeds', 'af', 'af.entity_id = entity.id'); + $subquery->condition('af.feeds_target_id', $echannel_id); + + $query->condition('entity.id', $subquery, 'NOT IN'); + } } diff --git a/src/QuestionInterface.php b/src/QuestionInterface.php index 3d24525..623dce6 100644 --- a/src/QuestionInterface.php +++ b/src/QuestionInterface.php @@ -6,13 +6,13 @@ use Drupal\Core\Entity\EntityPublishedInterface; interface QuestionInterface extends ContentEntityInterface, EntityPublishedInterface { - const STATE_OPEN = 0; - const STATE_RESERVED = 1; - const STATE_ANSWERED = 2; + public const STATE_OPEN = 0; + public const STATE_RESERVED = 1; + public const STATE_ANSWERED = 2; - const NO_NOTIFICATIONS = 0; - const NOTIFY_AUTHOR = 1; - const NOTIFY_SUBSCRIBERS = 2; + public const NO_NOTIFICATIONS = 0; + public const NOTIFY_AUTHOR = 1; + public const NOTIFY_SUBSCRIBERS = 2; public function getAdminNotes(); public function setAdminNotes($details); diff --git a/src/QuestionStorage.php b/src/QuestionStorage.php index 39675d0..17a6db0 100755 --- a/src/QuestionStorage.php +++ b/src/QuestionStorage.php @@ -11,7 +11,7 @@ public function findSimilarQuestions(QuestionInterface $question, $limit = 10) { return []; } - $tags = array_map(function($t) { return $t->id(); }, $tags); + $tags = array_map(fn($t) => $t->id(), $tags); $query = $this->database->select('asklib_questions', 'q') ->fields('q', ['id']) diff --git a/src/QuestionViewBuilder.php b/src/QuestionViewBuilder.php index 3eaf314..06330ef 100644 --- a/src/QuestionViewBuilder.php +++ b/src/QuestionViewBuilder.php @@ -18,7 +18,7 @@ public function buildComponents(array &$build, array $entities, array $displays, '#theme' => 'asklib_ref_question', '#weight' => -100, - '#url' => $question->urlInfo('add-form', ['query' => [ + '#url' => $question->toUrl('add-form', ['query' => [ 'ref' => $question->id(), ]]), ]; @@ -31,6 +31,12 @@ public function buildComponents(array &$build, array $entities, array $displays, $build[$delta]['comments']['#access'] = FALSE; } } + + // See the NOTE in asklib_preprocess_asklib_question about display managment. + foreach ($build as $delta => $current_build) { + $build[$delta]['title']['#label_display'] = 'hidden'; + } + } /** @@ -40,9 +46,7 @@ protected function sortTags(array &$tags) { $keys = Element::children($tags, TRUE); $items = []; - usort($keys, function($a, $b) use ($tags) { - return strcasecmp($tags[$a]['#title'], $tags[$b]['#title']); - }); + usort($keys, fn($a, $b) => strcasecmp($tags[$a]['#title'], $tags[$b]['#title'])); foreach ($keys as $i => $key) { $items[$i] = $tags[$key]; diff --git a/src/Routing/KeywordIndexRoutes.php b/src/Routing/KeywordIndexRoutes.php index 3485a9d..38a3747 100644 --- a/src/Routing/KeywordIndexRoutes.php +++ b/src/Routing/KeywordIndexRoutes.php @@ -8,7 +8,7 @@ use Symfony\Component\Routing\Route; class KeywordIndexRoutes { - private static $aliases = [ + private static array $aliases = [ 'fi' => '/kysy/asiasanat', 'en' => '/ask/keywords', 'sv' => '/fraga/amnesord' @@ -39,7 +39,7 @@ public static function access(AccountInterface $account) { $path = Drupal::request()->getPathInfo(); foreach (self::$aliases as $langcode => $alias) { - if ($active_langcode == $langcode && strpos($path, $alias) === 0) { + if ($active_langcode == $langcode && strpos($path, (string) $alias) === 0) { return AccessResult::allowed()->addCacheContexts(['languages:language_content']); } } diff --git a/src/Slugger/KeywordSlugger.php b/src/Slugger/KeywordSlugger.php index 4b8a61a..3f56b19 100644 --- a/src/Slugger/KeywordSlugger.php +++ b/src/Slugger/KeywordSlugger.php @@ -9,7 +9,7 @@ class KeywordSlugger extends DefaultSlugger { public function applies(EntityInterface $entity) { $vids = ['asklib_tags', 'finto']; - return $entity instanceof TermInterface && in_array($entity->getVocabularyId(), $vids, TRUE); + return $entity instanceof TermInterface && in_array($entity->bundle(), $vids, TRUE); } protected function extractTokens(EntityInterface $entity, $pattern, $max_words = 0) { diff --git a/src/Statistics/LibraryOverview.php b/src/Statistics/LibraryOverview.php index b3cdd7f..18900ec 100644 --- a/src/Statistics/LibraryOverview.php +++ b/src/Statistics/LibraryOverview.php @@ -2,6 +2,8 @@ namespace Drupal\asklib\Statistics; +use Drupal\Core\Database\Query\PagerSelectExtender; +use Drupal\Core\Database\Query\TableSortExtender; use PDO; use Drupal\Core\Form\FormStateInterface; use Drupal\asklib\QuestionInterface; @@ -26,7 +28,7 @@ public function alterForm(array &$form, FormStateInterface $form_state) { 'city' => $this->t('Municipality'), 'special' => $this->t('Special library'), ], - '#default_value' => isset($this->parameters['t']) ? $this->parameters['t'] : '', + '#default_value' => $this->parameters['t'] ?? '', ] ]; @@ -36,7 +38,7 @@ public function alterForm(array &$form, FormStateInterface $form_state) { 'name' => [ '#type' => 'textfield', '#title' => $this->t('Name'), - '#default_value' => isset($this->parameters['n']) ? $this->parameters['n'] : '', + '#default_value' => $this->parameters['n'] ?? '', '#size' => 20, ], ]; @@ -87,8 +89,8 @@ protected function countByLibrary() { ]; $query = $this->getQuery() - ->extend('Drupal\Core\Database\Query\PagerSelectExtender') - ->extend('Drupal\Core\Database\Query\TableSortExtender'); + ->extend(PagerSelectExtender::class) + ->extend(TableSortExtender::class); $query->innerJoin('taxonomy_term_field_data', 't', 'a.library = t.tid'); $query->addExpression('COUNT(*)', 'total'); $query->addExpression('MAX(a.answered)', 'last_answer'); diff --git a/src/Statistics/MunicipalityOverview.php b/src/Statistics/MunicipalityOverview.php index d671801..ccf103a 100644 --- a/src/Statistics/MunicipalityOverview.php +++ b/src/Statistics/MunicipalityOverview.php @@ -2,6 +2,8 @@ namespace Drupal\asklib\Statistics; +use Drupal\Core\Database\Query\PagerSelectExtender; +use Drupal\Core\Database\Query\TableSortExtender; use PDO; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; @@ -21,7 +23,7 @@ public function alterForm(array &$form, FormStateInterface $form_state) { 'name' => [ '#type' => 'textfield', '#title' => $this->t('Name'), - '#default_value' => isset($this->parameters['n']) ? $this->parameters['n'] : '', + '#default_value' => $this->parameters['n'] ?? '', '#size' => 30, ], ]; @@ -69,8 +71,8 @@ protected function countByMunicipality() { ]; $query = $this->getQuery() - ->extend('Drupal\Core\Database\Query\PagerSelectExtender') - ->extend('Drupal\Core\Database\Query\TableSortExtender'); + ->extend(PagerSelectExtender::class) + ->extend(TableSortExtender::class); $query->innerJoin('taxonomy_term_field_data', 't', 'q.municipality = t.tid'); $query->addExpression('COUNT(*)', 'total'); $query->addExpression('MAX(a.answered)', 'last_answer'); diff --git a/src/Statistics/Overview.php b/src/Statistics/Overview.php index 57dadeb..a14273e 100644 --- a/src/Statistics/Overview.php +++ b/src/Statistics/Overview.php @@ -128,7 +128,7 @@ protected function countByDelay() { $result = $query->execute()->fetchAll(PDO::FETCH_ASSOC); $rows = []; $rest = ['delay' => $this->t('@days days', ['@days' => '4+']), 'total' => 0]; - $total = array_reduce($result, function($total, $row) { return $total + $row['total']; }, 0); + $total = array_reduce($result, fn($total, $row) => $total + $row['total'], 0); foreach ($result as $row) { if ($row['delay'] <= 3) { @@ -213,16 +213,12 @@ protected function countByChannel() { $result = $query->execute()->fetchAll(PDO::FETCH_UNIQUE); - $data = array_map(function($c) use ($result) { - return [ - 'name' => $c->label(), - 'total' => isset($result[$c->id()]) ? $result[$c->id()]->total : 0, - ]; - }, $channels); + $data = array_map(fn($c) => [ + 'name' => $c->label(), + 'total' => isset($result[$c->id()]) ? $result[$c->id()]->total : 0, + ], $channels); - usort($data, function($a, $b) { - return strcasecmp($a['name'], $b['name']); - }); + usort($data, fn($a, $b) => strcasecmp($a['name'], $b['name'])); $table = [ '#type' => 'table', diff --git a/src/Statistics/PersonOverview.php b/src/Statistics/PersonOverview.php index 3bdd8e6..2403596 100644 --- a/src/Statistics/PersonOverview.php +++ b/src/Statistics/PersonOverview.php @@ -2,6 +2,8 @@ namespace Drupal\asklib\Statistics; +use Drupal\Core\Database\Query\PagerSelectExtender; +use Drupal\Core\Database\Query\TableSortExtender; use PDO; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; @@ -21,7 +23,7 @@ public function alterForm(array &$form, FormStateInterface $form_state) { 'name' => [ '#type' => 'textfield', '#title' => $this->t('User name'), - '#default_value' => isset($this->parameters['n']) ? $this->parameters['n'] : '', + '#default_value' => $this->parameters['n'] ?? '', '#size' => 30, ], ]; @@ -67,8 +69,8 @@ protected function countByUser() { ]; $query = $this->getQuery() - ->extend('Drupal\Core\Database\Query\PagerSelectExtender') - ->extend('Drupal\Core\Database\Query\TableSortExtender'); + ->extend(PagerSelectExtender::class) + ->extend(TableSortExtender::class); $query->innerJoin('users_field_data', 'u', 'a.user = u.uid'); $query->addExpression('COUNT(*)', 'total'); $query->addExpression('MAX(a.answered)', 'last_answer'); diff --git a/src/UserMailGroupHelper.php b/src/UserMailGroupHelper.php index 282a9d1..e0336c1 100644 --- a/src/UserMailGroupHelper.php +++ b/src/UserMailGroupHelper.php @@ -27,6 +27,7 @@ public function getGroupsForUsers(array $uids, $active_only = FALSE) { $storage = $this->entityManager->getStorage('taxonomy_term'); $query = $storage->getQuery() + ->accessCheck(false) ->condition('field_asklib_subscribers', $uids) ->sort('vid', 'DESC'); @@ -42,7 +43,7 @@ public function getGroupsForUsers(array $uids, $active_only = FALSE) { FROM {taxonomy_term__field_asklib_subscribers} WHERE field_asklib_subscribers_target_id IN (%s) ', $phs); - $smt = $this->database->prepareQuery($query); + $smt = $this->database->prepareStatement($query, []); $smt->execute(array_values($uids)); $tids = []; @@ -60,13 +61,12 @@ public function setGroupsForUser($uid, array $gids) { $storage = $this->entityManager->getStorage('taxonomy_term'); $tids = $storage->getQuery() ->condition('field_asklib_subscribers', $uid) + ->accessCheck(FALSE) ->execute(); // Filter user from terms that the user is not subscribed to anymore. foreach ($storage->loadMultiple($tids) as $term) { - $term->get('field_asklib_subscribers')->filter(function($field) use ($term, $uid, $gids) { - return $field->target_id != $uid || in_array($term->id(), $gids); - }); + $term->get('field_asklib_subscribers')->filter(fn($field) => $field->target_id != $uid || in_array($term->id(), $gids)); $term->save(); } @@ -88,7 +88,7 @@ public function getUserMainGroup($user_id) { $groups = $this->getGroupsForUser($user_id, TRUE); foreach ($groups as $i => $term) { - if ($term->getVocabularyId() == 'asklib_municipalities') { + if ($term->bundle() == 'asklib_municipalities') { return $term; } }