Рейтинг:1

Как реализовать TrustedCallbackInterface

флаг us

Я поддерживаю модуль, для которого у меня есть сторонняя сборка для разработчиков. я Д9 Эта проблема появился при использовании модуля, который в остальном работает в D8 и должен быть совместим с 8 и 9.

Модуль создает блоки с датами событий, извлеченными из службы Songkick, но на страницах D9 с включенным блоком songkick выдает эту ошибку:

Drupal\Core\Security\UntrustedCallbackException: визуализация #pre_render обратные вызовы должны быть методами класса, реализующего \Drupal\Core\Security\TrustedCallbackInterface или быть анонимным функция. Обратный вызов был _songkick_block_poweredby_prerender. Видеть https://www.drupal.org/node/2966725 в Drupal\Core\Render\Renderer->doTrustedCallback() (строка 96 /var/www/html/web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php).

Я простой создатель сайтов с ограниченным опытом кодирования, поэтому мне нужна помощь, чтобы решить эту проблему. В ошибке упоминается эта страница объясняя проблему.

В приведенном ниже коде из моих файлов .module упоминается pre_render.

/**
 * Реализует hook_block_view_alter().
 */
функция songkick_block_content_view_alter (массив и $ сборка) {
    $id = $build['#block_content']->id();
  $block = \Drupal\block_content\Entity\BlockContent::load($id);
  $block_type = $block->type[0]->target_id;
  если ($block_type == 'songkick_block') {
        $build['#pre_render'][] = '_songkick_block_poweredby_prerender';
    }
}

/**
 * Получите данные API предстоящих и прошлых событий.
 */
функция _songkick_block_poweredby_prerender (массив и сборка $) {
  $id = $build['#block_content']->id();
  $block = \Drupal\block_content\Entity\BlockContent::load($id);
  $block_type = $block->type[0]->target_id;
  если ($block_type == 'songkick_block') {
    // Получить данные пользовательских блоков.
      $artis_id = $block->field_artist_id[0]->значение;
      $upcoming_show = $block->field_display_upcoming_shows[0]->значение;
      $past_show = $block->field_display_past_shows[0]->значение;
      $event_details = $block->field_ticket_button[0]->значение;
      $events_data = [
        'event_details' => $event_details,
        'предстоящее_шоу' => $предстоящее_шоу,
        'прошлое_шоу' => $прошлое_шоу
      ];
      $events_data = [
          '#theme' => 'songkick_events',
          '#events_data' => $events_data
      ];

        $client = \Drupal::httpClient();
        $api_key = \Drupal::config('songkick.settings')->get('songkick_key');
        $url = 'http://api.songkick.com/api/3.0/artists/';

        // Данные предстоящего события.
    если ($upcoming_show == '1') {
            $апиключ = $url. $artis_id. "/calendar.json" . "?apikey=". $апи_ключ;
            $request = $client->get($apikey);
            $body = $request->getBody()->getContents();
            $AllData = (массив)json_decode($body);
            // Данные последней страницы
            $per_page = $AllData['resultsPage']->на страницу;
            $total_entry = $AllData['resultsPage']->totalEntries;
            $page = (int)($total_entry / $per_page);
            //$mainData = $AllData['resultsPage']->результаты->событие;
            $temp_var = [];
            для ($x = $page; $x >= 0; $x--){ 
                $final_api_key = $apikey. "&страница=" . $х;
                $upcoming_event_request = $client->get($final_api_key);
                $upcoming_event_body = $upcoming_event_request->getBody()->getContents();
                $UpcomingEventAllData = json_decode($upcoming_event_body);
                $mainData = array_reverse($UpcomingEventAllData->страница результатов->результаты->событие);

                //$temp_data[] = $mainData;
                foreach ($mainData как $value) {
                    $temp_var[] = $значение;
                }

            }
            $upcoming_events_data = [
          '#theme' => 'songkick_events',
          '#upcoming_event' => $temp_var
        ];
    }
    еще{
            $upcoming_events_data = [
          '#theme' => 'songkick_events',
          '#upcoming_event' => ''
        ];  
    }

    // Данные прошлых событий.
    если ($past_show == '1') {
            $апиключ = $url. $artis_id. "/гигография.json" . "?apikey=". $апи_ключ;
            $request = $client->get($apikey);
            $body = $request->getBody()->getContents();
            $AllData = (массив)json_decode($body);

            // Данные последней страницы
            $per_page = $AllData['resultsPage']->на страницу;
            $total_entry = $AllData['resultsPage']->totalEntries;
            $page = (int)($total_entry / $per_page);

            $temp_var = [];
            для ($x = $page; $x >= 0; $x--){ 
                $final_api_key = $apikey. "&страница=" . $х;
                $past_event_request = $client->get($final_api_key);
                $past_event_body = $past_event_request->getBody()->getContents();
                $PastEventAllData = json_decode($past_event_body);
                $mainData = array_reverse($PastEventAllData->resultsPage->results->event);

                //$temp_data[] = $mainData;
                foreach ($mainData как $value) {
                    $temp_var[] = $значение;
                }
            }
            //$final_api_key = $apikey. "&страница=" . $страница;
            // $past_event_request = $client->get($final_api_key);
            // $past_event_body = $past_event_request->getBody()->getContents();
            // $PastEventAllData = (массив)json_decode($past_event_body);
            // $mainData = array_reverse($PastEventAllData['resultsPage']->результаты->событие);
            $прошлые_события_данные = [
          '#theme' => 'songkick_events',
          '#past_event' => $temp_var
        ];
    }
    еще{
            $прошлые_события_данные = [
          '#theme' => 'songkick_events',
          '#прошедшее_событие' => ''
        ];
    }

    // Объединение данных о предстоящих и прошлых событиях.
    $event_data = array_merge($upcoming_events_data,$past_events_data,$events_data);

    // Возвращаем данные о событиях.
        вернуть $event_data;
  }
}

Я пытался следовать инструкциям в этот комментарий и добавили файл с именем SongkickBlockPoweredByViewBuilder.php в папку src с этим кодом:

<?php

пространство имен Drupal\Songkick;

используйте Drupal\Core\Security\TrustedCallbackInterface;

/**
 * Обеспечивает надежный обратный вызов для блока Songkick Poweredby.
 *
 */
class SongkickBlockPoweredByViewBuilder реализует TrustedCallbackInterface {

    /**
     * {@inheritdoc}
     */
    общедоступная статическая функция trustCallbacks() {
     возврат ['preRender'];    
   }
 
   /**
    * Устанавливает обратный вызов Songkick - #pre_render.
    */
   общедоступная статическая функция preRender($build) {
     $count = $build['content']['#count'];
     $build['content']['#count_text'] = \Drupal::translation()->formatPlural($count, '(@count)', '(@count)');
     вернуть $сборку;
   }
 
 }

И я добавил в свой файл .module следующее:

используйте Drupal\Songkick\SongkickBlockPoweredByViewBuilder;

/**
 * Реализует TrustedCallbackInterface
 */
function _songkick_block_poweredby_prerender (массив & $ build, Drupal \ Core \ Block \ BlockPluginInterface $ block) {
  $build['#pre_render'][] = [SongkickBlockPoweredByViewBuilder::class, 'preRender'];
}

Затем сайт выдает эту фатальную ошибку:

Неустранимая ошибка: невозможно повторно объявить _songkick_block_poweredby_prerender() (ранее объявлено в /var/www/html/web/modules/contrib/songkick/songkick.module:14) в /var/www/html/web/modules/contrib/songkick/songkick.module в строке 51

Фатальная ошибка исчезнет, ​​если я удалю объявление в строке 14, но исходная ошибка сохранится. Я не понимаю, как определить функцию в строке 51 таким образом, чтобы решить проблему. Строка 51 начинается сразу после этого комментария в приведенном выше отрывке из файла .module:

/*** Получить данные API предстоящих и прошлых событий. */

Какие-нибудь советы?

флаг cn
Drupal выдает предупреждение с конкретной ссылкой, объясняющей проблему. Если вы не понимаете связанные документы - что именно вы не понимаете? И всегда помогает, если вы публикуете фактический код, который вызывает проблему;)
флаг us
Действительные баллы @PatrickKenny, спасибо. Я отредактировал исходный пост, чтобы включить эти вещи.
Lambic avatar
флаг ph
Этот комментарий и ответ на него по проблеме, указанной в сообщении об ошибке, содержат примеры того, что вам нужно сделать: https://www.drupal.org/node/2966725#comment-13948868.
флаг us
Большое спасибо @Lambic. Я просто старался изо всех сил, и, должно быть, я сделал что-то не так, так как это приводит к фатальной ошибке. Я обновил свой вопрос с шагами, которые я предпринял. Могу я уговорить вас взглянуть?
Lambic avatar
флаг ph
Похоже, у вас есть одна и та же функция, определенная дважды в songkick.module, один раз в строке 14 и снова в строке 51.
флаг us
Ясно спасибо. Я добавил эту деталь к вопросу. Любые идеи о том, как я могу заменить старое объявление (строка 51) новым (строка 14), которое реализует TrustedCallbackInterface?
apaderno avatar
флаг us
Вопросы не предназначены для переписки между пользователем, который задает вопрос, и пользователями, которые на него отвечают. После ответа на вопрос его нельзя редактировать, если редактирование меняет значение вопроса или добавляет дополнительный вопрос (* Я сделал, как сказано в ответе, но теперь у меня другая проблема. *)
Рейтинг:4
флаг fr

У вас есть правильная идея, есть только несколько деталей, которые нужно исправить.

TrustedCallbackInterface был впервые добавлен в Drupal 8.8; его не было до Drupal 8.8. Хотя это необязательно в Drupal 8.8 и 8.9, обязательное в Drupal 9. Итак, ваш модуль не совместим с Drupal 9, пока вы не внесете это изменение.

Сначала скопируйте все тело исходной версии _songkick_block_poweredby_prerender() в твой общедоступная статическая функция preRender($build). Это все, что должно быть в теле предварительная визуализация () метод.

Во-вторых, удалите функцию _songkick_block_poweredby_prerender() (обе копии) из songkick.module. Вам это больше не нужно, потому что вы поместили этот код в Drupal\songkick\SongkickBlockPoweredByViewBuilder.

Теперь поместите используйте Drupal\songkick\SongkickBlockPoweredByViewBuilder; оператор в верхней части songkick.module со всеми остальными операторами использования. Затем измените это утверждение:

$build['#pre_render'][] = '_songkick_block_poweredby_prerender';

вместо этого указать на ваш новый код. Как это:

$build['#pre_render'][] = [SongkickBlockPoweredByViewBuilder::class, 'preRender'];

Также обратите внимание, что правильное пространство имен имеет строчную букву «s» в слове «songkick». Оно должно совпадать с именем компьютера модуля, а в именах компьютеров нельзя использовать заглавные буквы. Поэтому вам нужно убедиться, что пространство имен декларация в SongkickBlockPoweredByViewBuilder использует нижний регистр, и что ваш использовать Оператор в songkick.module использует строчные буквы.

Drupal требователен к именованию, поэтому также убедитесь, что если ваш файл .module находится в songkick/songkick.module, класс SongkickBlockPoweredByViewBuilder в songkick/src/SongkickBlockPoweredByViewBuilder.php

флаг us
Большое спасибо. Первоначальная ошибка исчезла, но блок больше не отображает список событий, а только настройки блока. Я обновил вопрос, чтобы отразить предпринятые шаги и новые отчеты журнала. Любые идеи будут оценены по достоинству.
флаг fr
Вы не удалили эти три строки из вашего preRender(), поэтому вы возвращаетесь из функции еще до того, как ваш код данных события будет запущен: `$count = $build['content']['#count']; $build['content']['#count_text'] = \Drupal::translation()->formatPlural($count, '(@count)', '(@count)'); вернуть $сборка;`
флаг fr
И на данный момент мы отлаживаем ваш код, который выходит за рамки этой проблемы и не совсем подходит для StackExchange.
флаг us
Верный момент, извините за это. В любом случае, большое спасибо за вашу помощь. Я приму ваш ответ сейчас.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.