Puncte:1

Cum se implementează TrustedCallbackInterface

drapel us

Mențin un modul pentru care am avut un dezvoltator terță parte pentru mine. eu D9 această problemă a apărut când se folosește modulul care altfel funcționează în D8 și ar trebui să fie compatibil cu 8 și 9.

Modulul creează blocuri cu datele evenimentului extrase din serviciul Songkick, dar pe paginile D9 cu un bloc Songkick activat, aruncă această eroare:

Drupal\Core\Security\UntrustedCallbackException: Redați #pre_render callback-urile trebuie să fie metode ale unei clase care implementează \Drupal\Core\Security\TrustedCallbackInterface sau fiți un anonim funcţie. Reapelarea a fost _songkick_block_poweredby_prerender. Vedea https://www.drupal.org/node/2966725 în Drupal\Core\Render\Renderer->doTrustedCallback() (linia 96 din /var/www/html/web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php).

Sunt un simplu constructor de site-uri cu experiență limitată de codare, așa că caut ajutor pentru a remedia problema. Eroarea menţionează această pagină explicând problema.

Codul de mai jos din fișierele mele .module include pre_render în mențiune.

/**
 * Implementează hook_block_view_alter().
 */
funcția songkick_block_content_view_alter(array &$build) {
    $id = $build['#block_content']->id();
  $bloc = \Drupal\block_content\Entity\BlockContent::load($id);
  $block_type = $block->type[0]->target_id;
  dacă ($block_type == 'songkick_block') {
        $build['#pre_render'][] = '_songkick_block_poweredby_prerender';
    }
}

/**
 * Obțineți date API pentru evenimente viitoare și trecute.
 */
funcția _songkick_block_poweredby_prerender(array &$build) {
  $id = $build['#block_content']->id();
  $bloc = \Drupal\block_content\Entity\BlockContent::load($id);
  $block_type = $block->type[0]->target_id;
  dacă ($block_type == 'songkick_block') {
    // Obține date personalizate Blocks.
      $artis_id = $bloc->field_artist_id[0]->valoare;
      $upcoming_show = $bloc->field_display_upcoming_shows[0]->valoare;
      $past_show = $bloc->field_display_past_shows[0]->valoare;
      $detalii_eveniment = $block->field_ticket_button[0]->valoare;
      $date_evenimente = [
        'event_details' => $event_details,
        'upcoming_show' => $upcoming_show,
        'past_show' => $past_show
      ];
      $date_evenimente = [
          '#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/';

        // Date despre evenimente viitoare.
    dacă ($upcoming_show == '1') {
            $apikey = $url . $artis_id. „/calendar.json” . „?apikey=". $api_key;
            $cerere = $client->get($apikey);
            $corp = $cerere->getBody()->getContents();
            $AllData = (matrice)json_decode($corp);
            // Datele ultimei pagini
            $per_page = $AllData['resultsPage']->perPage;
            $total_entry = $AllData['resultsPage']->totalEntries;
            $pagina = (int)($total_entry / $per_page);
            //$mainData = $AllData['resultsPage']->results->eveniment;
            $temp_var = [];
            pentru ($x = $pagina; $x >= 0; $x--){ 
                $final_api_key = $apikey . „&page=". $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 ca $valoare) {
                    $temp_var[] = $valoare;
                }

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

    // Date despre evenimentele trecute.
    if ($past_show == '1') {
            $apikey = $url . $artis_id. „/gigography.json” . „?apikey=". $api_key;
            $cerere = $client->get($apikey);
            $corp = $cerere->getBody()->getContents();
            $AllData = (matrice)json_decode($corp);

            // Datele ultimei pagini
            $per_page = $AllData['resultsPage']->perPage;
            $total_entry = $AllData['resultsPage']->totalEntries;
            $pagina = (int)($total_entry / $per_page);

            $temp_var = [];
            pentru ($x = $pagina; $x >= 0; $x--){ 
                $final_api_key = $apikey . „&page=". $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 ca $valoare) {
                    $temp_var[] = $valoare;
                }
            }
            //$final_api_key = $apikey . „&page=". $pagina;
            // $past_event_request = $client->get($final_api_key);
            // $past_event_body = $past_event_request->getBody()->getContents();
            // $PastEventAllData = (matrice)json_decode($past_event_body);
            // $mainData = array_reverse($PastEventAllData['resultsPage']->results->event);
            $date_evenimente_trecute = [
          '#theme' => 'songkick_events',
          '#past_event' => $temp_var
        ];
    }
    altfel{
            $date_evenimente_trecute = [
          '#theme' => 'songkick_events',
          '#past_event' => ''
        ];
    }

    // Îmbină datele evenimentelor viitoare și trecute.
    $event_data = array_merge($date_evenimente_upcoming,$date_evenimente_trecute,$date_evenimente);

    // Returnează datele evenimentelor.
        returnează $date_eveniment;
  }
}

Am încercat să urmez instrucțiunile din acest comentariu și am adăugat un fișier numit SongkickBlockPoweredByViewBuilder.php în folderul src cu acest cod:

<?php

spațiu de nume Drupal\Songkick;

utilizați Drupal\Core\Security\TrustedCallbackInterface;

/**
 * Oferă un apel invers de încredere pentru blocul Songkick Poweredby.
 *
 */
clasa SongkickBlockPoweredByViewBuilder implementează TrustedCallbackInterface {

    /**
     * {@inheritdoc}
     */
    funcție publică statică trustedCallbacks() {
     return ['preRender'];    
   }
 
   /**
    * Setează Songkick - #pre_render callback.
    */
   funcție publică statică preRender($build) {
     $count = $build['conținut']['#count'];
     $build['content']['#count_text'] = \Drupal::translation()->formatPlural($count, '(@count)', '(@count)');
     returnează $build;
   }
 
 }

Și am adăugat următoarele în fișierul meu .module:

utilizați Drupal\Songkick\SongkickBlockPoweredByViewBuilder;

/**
 * Implementează TrustedCallbackInterface
 */
funcția _songkick_block_poweredby_prerender(array &$build, Drupal\Core\Block\BlockPluginInterface $block) {
  $build['#pre_render'][] = [SongkickBlockPoweredByViewBuilder::class, 'preRender'];
}

Apoi site-ul aruncă această eroare fatală:

Eroare fatală: nu se poate redeclara _songkick_block_poweredby_prerender() (declarat anterior în /var/www/html/web/modules/contrib/songkick/songkick.module:14) în /var/www/html/web/modules/contrib/songkick/songkick.module pe linia 51

Eroarea fatală dispare dacă elimin declarația din linia 14, dar eroarea inițială persistă. Nu știu cum să definesc funcția din linia 51 într-un mod care să rezolve problema. Linia 51 începe imediat după acest comentariu în fragmentul de mai sus din fișierul .module:

/*** Obțineți date API pentru evenimente viitoare și trecute. */

Orice sfaturi?

drapel cn
Drupal vă oferă un avertisment cu un link specific care explică problema. Dacă nu înțelegeți documentele legate de link-- ce este ceea ce nu înțelegeți? Și întotdeauna ajută dacă postezi codul real care cauzează problema ;)
drapel us
Puncte valide @PatrickKenny, mulțumesc. Am editat postarea originală pentru a include acele lucruri.
Lambic avatar
drapel ph
Acest comentariu și răspunsul la acesta privind problema legată de mesajul de eroare conțin exemple de ceea ce trebuie să faceți: https://www.drupal.org/node/2966725#comment-13948868
drapel us
Mulțumesc mult @Lambic. Tocmai am încercat tot posibilul și trebuie să fi făcut ceva greșit, deoarece duce la o eroare fatală. Mi-am actualizat întrebarea cu pașii pe care i-am făcut. Pot să te conving să arunci o privire?
Lambic avatar
drapel ph
Se pare că aveți aceeași funcție definită de două ori în songkick.module, o dată la linia 14 și din nou la linia 51
drapel us
Văd, mulțumesc. Am adăugat acel detaliu la întrebare. Aveți informații despre cum pot înlocui vechea declarație (linia 51) cu cea nouă (linia 14) care implementează TrustedCallbackInterface?
apaderno avatar
drapel us
Întrebările nu sunt pentru un dus și înapoi între utilizatorul care pune întrebarea și utilizatorii care îi răspund. Odată ce se răspunde la întrebare, aceasta nu poate fi editată, dacă editarea schimbă sensul întrebării sau adaugă o întrebare ulterioară (*Am făcut așa cum spune răspunsul, dar acum am o altă problemă.*)
Puncte:4
drapel fr

Ai ideea potrivită, sunt doar câteva detalii care trebuie remediate.

TrustedCallbackInterface a fost adăugat pentru prima dată la Drupal 8.8; nu a existat înainte de Drupal 8.8. Deși este opțional în Drupal 8.8 și 8.9, este obligatoriu în Drupal 9. Deci modulul tău nu este compatibil cu Drupal 9 până când faceți această modificare.

Mai întâi, copiați întregul corp al versiunii originale a _songkick_block_poweredby_prerender() în tine funcție publică statică preRender($build). Asta este tot ce ar trebui să fie în corpul preRender() metodă.

În al doilea rând, ștergeți funcția _songkick_block_poweredby_prerender() (ambele copii) de la songkick.module. Nu mai aveți nevoie pentru că ați introdus acel cod Drupal\songkick\SongkickBlockPoweredByViewBuilder.

Acum pune utilizați Drupal\songkick\SongkickBlockPoweredByViewBuilder; declarație în partea de sus a songkick.module cu toate celelalte instrucțiuni de utilizare. Apoi schimbați această afirmație:

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

pentru a indica în schimb noul tău cod. Ca aceasta:

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

De asemenea, rețineți că spațiul de nume corect are un „s” mic în „songkick”. Acesta trebuie să fie același cu numele mașinii modulului, iar numele mașinii nu permit litere mari. Deci trebuie să vă asigurați că spatiu de nume declarație în SongkickBlockPoweredByViewBuilder folosește literele mici și că dvs utilizare declarația din songkick.module folosește literele mici.

Drupal este pretențios în ceea ce privește denumirea, așa că, de asemenea, asigurați-vă că dacă fișierul dvs. .module este în songkick/songkick.modul, clasa SongkickBlockPoweredByViewBuilder este in songkick/src/SongkickBlockPoweredByViewBuilder.php

drapel us
Multumesc mult. Eroarea originală a dispărut, dar blocul nu mai redă lista de evenimente, ci doar setările blocului. Am actualizat întrebarea pentru a reflecta pașii parcurși și noile rapoarte de jurnal. Orice perspectivă ar fi apreciată masiv.
drapel fr
Nu ați eliminat aceste trei linii din preRender(), așa că vă întoarceți din funcție înainte ca codul de date al evenimentului să fie chiar rulat: `$count = $build['content']['#count']; $build['content']['#count_text'] = \Drupal::translation()->formatPlural($count, '(@count)', '(@count)'); returnează $build;`
drapel fr
Și în acest moment, vă depanăm codul, care este în afara domeniului de aplicare al acestei probleme și nu este cu adevărat adecvat pentru StackExchange.
drapel us
Punct valid, scuze pentru asta. Oricum, multumesc mult pentru ajutor. Accept răspunsul tău acum.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.