Điểm:1

Cách triển khai TrustedCallbackInterface

lá cờ us

Tôi đang duy trì một mô-đun mà tôi đã có một nhà phát triển bên thứ 3 xây dựng cho mình. Tôi D9 vấn đề này đã xuất hiện khi sử dụng mô-đun hoạt động trong D8 và phải tương thích với 8 & 9.

Mô-đun tạo các khối có ngày sự kiện được lấy từ dịch vụ Songkick nhưng trên các trang D9 có bật khối songkick sẽ gây ra lỗi này:

Drupal\Core\Security\UntrustedCallbackException: Kết xuất #pre_render các cuộc gọi lại phải là các phương thức của một lớp thực hiện \Drupal\Core\Security\TrustedCallbackInterface hoặc ẩn danh chức năng. Cuộc gọi lại là _songkick_block_poweredby_prerender. Nhìn thấy https://www.drupal.org/node/2966725 Trong Drupal\Core\Render\Renderer->doTrustedCallback() (dòng 96 của /var/www/html/web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php).

Tôi chỉ là một người xây dựng trang web với kinh nghiệm mã hóa hạn chế nên tôi đang tìm trợ giúp để khắc phục sự cố. Lỗi đề cập trang này giải thích vấn đề.

Mã bên dưới từ các tệp .module của tôi bao gồm pre_render được đề cập.

/**
 * Triển khai hook_block_view_alter().
 */
hàm songkick_block_content_view_alter(mảng &$build) {
    $id = $build['#block_content']->id();
  $block = \Drupal\block_content\Entity\BlockContent::load($id);
  $block_type = $block->type[0]->target_id;
  if ($block_type == 'songkick_block') {
        $build['#pre_render'][] = '_songkick_block_poweredby_prerender';
    }
}

/**
 * Nhận dữ liệu API sự kiện sắp tới và trong quá khứ.
 */
function _songkick_block_poweredby_prerender(mảng &$build) {
  $id = $build['#block_content']->id();
  $block = \Drupal\block_content\Entity\BlockContent::load($id);
  $block_type = $block->type[0]->target_id;
  if ($block_type == 'songkick_block') {
    // Nhận dữ liệu Khối tùy chỉnh.
      $artis_id = $block->field_artist_id[0]->value;
      $upcoming_show = $block->field_display_upcoming_shows[0]->value;
      $past_show = $block->field_display_past_shows[0]->value;
      $event_details = $block->field_ticket_button[0]->value;
      $sự_kiện_dữ_liệu = [
        'event_details' => $event_details,
        'upcoming_show' => $upcoming_show,
        'past_show' => $past_show
      ];
      $sự_kiện_dữ_liệu = [
          '#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/';

        // Dữ liệu sự kiện sắp tới.
    if ($upcoming_show == '1') {
            $apikey = $url . $artis_id. "/calendar.json" . "?apikey=". $api_key;
            $request = $client->get($apikey);
            $body = $request->getBody()->getContents();
            $AllData = (mảng)json_decode($body);
            // Dữ liệu trang cuối
            $per_page = $AllData['resultsPage']->perPage;
            $total_entry = $AllData['resultsPage']->totalEntries;
            $page = (int)($total_entry / $per_page);
            //$mainData = $AllData['resultsPage']->results->event;
            $temp_var = [];
            for ($x = $page; $x >= 0; $x--){ 
                $final_api_key = $apikey . "&trang=" . $x;
                $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->resultsPage->results->event);

                //$temp_data[] = $mainData;
                foreach ($mainData dưới dạng $value) {
                    $temp_var[] = $value;
                }

            }
            $upcoming_events_data = [
          '#theme' => 'songkick_events',
          '#upcoming_event' => $temp_var
        ];
    }
    khác{
            $upcoming_events_data = [
          '#theme' => 'songkick_events',
          '#sự kiện_sắp tới' => ''
        ];  
    }

    // Dữ liệu sự kiện trong quá khứ.
    nếu ($past_show == '1') {
            $apikey = $url . $artis_id. "/gigography.json" . "?apikey=". $api_key;
            $request = $client->get($apikey);
            $body = $request->getBody()->getContents();
            $AllData = (mảng)json_decode($body);

            // Dữ liệu trang cuối
            $per_page = $AllData['resultsPage']->perPage;
            $total_entry = $AllData['resultsPage']->totalEntries;
            $page = (int)($total_entry / $per_page);

            $temp_var = [];
            for ($x = $page; $x >= 0; $x--){ 
                $final_api_key = $apikey . "&trang=" . $x;
                $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 dưới dạng $value) {
                    $temp_var[] = $value;
                }
            }
            //$final_api_key = $apikey . "&trang=" . trang $;
            // $past_event_request = $client->get($final_api_key);
            // $past_event_body = $past_event_request->getBody()->getContents();
            // $PastEventAllData = (mảng)json_decode($past_event_body);
            // $mainData = array_reverse($PastEventAllData['resultsPage']->results->event);
            $past_events_data = [
          '#theme' => 'songkick_events',
          '#past_event' => $temp_var
        ];
    }
    khác{
            $past_events_data = [
          '#theme' => 'songkick_events',
          '#sự_kiện_quá_khứ' => ''
        ];
    }

    // Hợp nhất dữ liệu sự kiện sắp tới và quá khứ.
    $event_data = array_merge($upcoming_events_data,$past_events_data,$events_data);

    // Trả về dữ liệu sự kiện.
        trả lại dữ liệu sự kiện $;
  }
}

Tôi đã thử làm theo hướng dẫn trong bình luận này và đã thêm một tệp có tên SongkickBlockPoweredByViewBuilder.php trong thư mục src với mã này:

<?php

không gian tên Drupal\Songkick;

sử dụng Drupal\Core\Security\TrustedCallbackInterface;

/**
 * Cung cấp một cuộc gọi lại đáng tin cậy cho khối Songkick Poweredby.
 *
 */
lớp SongkickBlockPoweredByViewBuilder triển khai TrustedCallbackInterface {

    /**
     * {@inheritdoc}
     */
    hàm tĩnh công khai TrustedCallbacks() {
     trả về ['kết xuất trước'];    
   }
 
   /**
    * Đặt Songkick - gọi lại #pre_render.
    */
   hàm tĩnh công cộng preRender($build) {
     $count = $build['content']['#count'];
     $build['content']['#count_text'] = \Drupal::translation()->formatPlural($count, '(@count)', '(@count)');
     trả lại bản dựng $;
   }
 
 }

Và tôi đã thêm phần sau vào tệp .module của mình:

sử dụng Drupal\Songkick\SongkickBlockPoweredByViewBuilder;

/**
 * Triển khai TrustedCallbackInterface
 */
function _songkick_block_poweredby_prerender(mảng &$build, Drupal\Core\Block\BlockPluginInterface $block) {
  $build['#pre_render'][] = [SongkickBlockPoweredByViewBuilder::class, 'preRender'];
}

Sau đó, trang web đưa ra lỗi nghiêm trọng này:

Lỗi nghiêm trọng: Không thể khai báo lại _songkick_block_poweredby_prerender() (được khai báo trước đây trong /var/www/html/web/modules/contrib/songkick/songkick.module:14) trong /var/www/html/web/modules/contrib/songkick/songkick.module trên dòng 51

Lỗi nghiêm trọng sẽ biến mất nếu tôi xóa khai báo ở dòng 14, nhưng lỗi ban đầu vẫn tồn tại. Tôi không biết làm thế nào để xác định chức năng trong dòng 51 theo cách giải quyết vấn đề. Dòng 51 bắt đầu ngay sau nhận xét này trong đoạn trích trên từ tệp .module:

/*** Nhận dữ liệu API về các sự kiện sắp diễn ra và trước đây. */

Có mẹo nào không?

lá cờ cn
Drupal đưa ra cảnh báo cho bạn với một liên kết cụ thể giải thích vấn đề. Nếu bạn không hiểu các tài liệu được liên kết-- bạn không hiểu điều gì? Và nó luôn hữu ích nếu bạn đăng mã thực gây ra sự cố;)
lá cờ us
Điểm hợp lệ @PatrickKenny, cảm ơn. Tôi đã chỉnh sửa bài viết gốc để bao gồm những điều đó.
Lambic avatar
lá cờ ph
Nhận xét này và câu trả lời cho vấn đề được liên kết trong thông báo lỗi chứa các ví dụ về những gì bạn cần làm: https://www.drupal.org/node/2966725#comment-13948868
lá cờ us
Cảm ơn rất nhiều @Lambic. Tôi chỉ cố gắng hết sức và chắc hẳn tôi đã làm sai điều gì đó vì nó dẫn đến một lỗi nghiêm trọng. Tôi đã cập nhật câu hỏi của mình với các bước tôi đã thực hiện. Tôi có thể thuyết phục bạn xem qua không?
Lambic avatar
lá cờ ph
Có vẻ như bạn đã xác định cùng một chức năng hai lần trong songkick.module, một lần ở dòng 14 và một lần nữa ở dòng 51
lá cờ us
Tôi thấy, cảm ơn. Tôi đã thêm chi tiết đó vào câu hỏi. Bất kỳ thông tin chi tiết nào về cách tôi có thể thay thế khai báo cũ (dòng 51) bằng khai báo mới (dòng 14) triển khai TrustedCallbackInterface?
apaderno avatar
lá cờ us
Các câu hỏi không dành cho sự trao đổi qua lại giữa người dùng đặt câu hỏi và người dùng trả lời câu hỏi đó. Sau khi câu hỏi được trả lời, nó không thể được chỉnh sửa, nếu phần chỉnh sửa làm thay đổi ý nghĩa của câu hỏi hoặc nó thêm một câu hỏi tiếp theo (*Tôi đã làm như câu trả lời nói, nhưng bây giờ tôi gặp vấn đề khác.*)
Điểm:4
lá cờ fr

Bạn có ý tưởng đúng, chỉ có một vài chi tiết cần được sửa chữa.

TrustedCallbackInterface lần đầu tiên được thêm vào Drupal 8.8; nó không tồn tại trước Drupal 8.8. Mặc dù nó là tùy chọn trong Drupal 8.8 và 8.9, nhưng nó là bắt buộc trong Drupal 9. Vì vậy, mô-đun của bạn không phải tương thích với Drupal 9 cho đến khi bạn thực hiện thay đổi này.

Đầu tiên, sao chép toàn bộ nội dung của phiên bản gốc của bạn _songkick_block_poweredby_prerender() vào của bạn chức năng tĩnh công khai preRender($build). Đó là tất cả những gì nên có trong cơ thể của kết xuất trước() phương pháp.

Thứ hai, xóa chức năng _songkick_block_poweredby_prerender() (cả hai bản sao) từ songkick.module. Bạn không cần nó nữa vì bạn đã đặt mã đó vào Drupal\songkick\SongkickBlockPoweredByViewBuilder.

Bây giờ đặt sử dụng Drupal\songkick\SongkickBlockPoweredByViewBuilder; câu lệnh ở đầu songkick.module với tất cả các câu lệnh sử dụng khác. Sau đó thay đổi tuyên bố này:

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

để trỏ đến mã mới của bạn thay thế. Như thế này:

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

Cũng lưu ý rằng không gian tên chính xác có chữ 's' viết thường trong 'songkick'. Tên này phải giống với tên máy của mô-đun và tên máy không cho phép viết hoa. Vì vậy, bạn cần đảm bảo rằng không gian tên khai báo trong SongkickBlockPoweredByViewBuilder sử dụng chữ thường, và rằng bạn sử dụng câu lệnh trong songkick.module sử dụng chữ thường.

Drupal kén chọn cách đặt tên, vì vậy hãy đảm bảo rằng nếu tệp .module của bạn nằm trong songkick/songkick.module, lớp SongkickBlockPoweredByViewBuilder trong songkick/src/SongkickBlockPoweredByViewBuilder.php

lá cờ us
Cám ơn rất nhiều. Lỗi ban đầu đã biến mất nhưng khối không hiển thị danh sách các sự kiện nữa, chỉ hiển thị cài đặt khối. Tôi đã cập nhật câu hỏi để phản ánh các bước đã thực hiện và báo cáo nhật ký mới. Bất kỳ thông tin chi tiết nào sẽ được đánh giá cao.
lá cờ fr
Bạn đã không xóa ba dòng này khỏi preRender() của mình, vì vậy bạn đang quay lại từ chức năng trước khi mã dữ liệu sự kiện của bạn thậm chí được chạy: `$count = $build['content']['#count']; $build['content']['#count_text'] = \Drupal::translation()->formatPlural($count, '(@count)', '(@count)'); trả về $build;`
lá cờ fr
Và tại thời điểm này, chúng tôi đang gỡ lỗi mã của bạn, mã này nằm ngoài phạm vi của vấn đề này và không thực sự phù hợp với StackExchange.
lá cờ us
Điểm hợp lệ, xin lỗi về điều đó. Dù sao, cảm ơn rất nhiều vì sự giúp đỡ của bạn. Tôi sẽ chấp nhận câu trả lời của bạn bây giờ.

Đăng câu trả lời

Hầu hết mọi người không hiểu rằng việc đặt nhiều câu hỏi sẽ mở ra cơ hội học hỏi và cải thiện mối quan hệ giữa các cá nhân. Ví dụ, trong các nghiên cứu của Alison, mặc dù mọi người có thể nhớ chính xác có bao nhiêu câu hỏi đã được đặt ra trong các cuộc trò chuyện của họ, nhưng họ không trực giác nhận ra mối liên hệ giữa câu hỏi và sự yêu thích. Qua bốn nghiên cứu, trong đó những người tham gia tự tham gia vào các cuộc trò chuyện hoặc đọc bản ghi lại các cuộc trò chuyện của người khác, mọi người có xu hướng không nhận ra rằng việc đặt câu hỏi sẽ ảnh hưởng—hoặc đã ảnh hưởng—mức độ thân thiện giữa những người đối thoại.