Programowanie z API
Programowanie z APIUżywanie kodu DRY do renderowania bloków po stronie serwera (PHP) i klienta (JS)

Używanie kodu DRY do renderowania bloków po stronie serwera (PHP) i klienta (JS)

Bloki dynamiczne (Gutenberg) to bloki, które budują swoją strukturę i zawartość dynamicznie w momencie renderowania bloku na front-endzie.

Renderowanie bloku dynamicznego na front-endzie (aby wyświetlić go w edytorze WordPress) i po stronie serwera (aby wygenerować HTML dla wpisu na blogu) zazwyczaj pobiera dane na dwa różne sposoby:

  • Łącząc się z API po stronie klienta (JavaScript)
  • Wywołując funkcje WordPress po stronie serwera (PHP)

Dzięki Gato GraphQL i jego rozszerzeniom możliwe jest uczynienie tej logiki DRY, posiadając jedno źródło prawdy do pobierania danych zarówno po stronie klienta, jak i serwera. Sprawdźmy, jak to zrobić.

Przechowywanie queries GraphQL w plikach .gql

Aby połączyć się z serwerem GraphQL po stronie klienta, zazwyczaj wykonujemy query GraphQL osadzone w kodzie JavaScript, w ten sposób:

const response = await fetch(endpoint, {
  body: JSON.stringify({
    query: `
      query {
        posts {
          id
          title
          author {
            id
            name
          }
        }
      }
    `
  )
} );

Możemy alternatywnie przechowywać query GraphQL w pliku .gql (lub .graphql) i importować jego zawartość za pomocą raw-loader Webpack:

// File webpack.config.js
const config = require( '@wordpress/scripts/config/webpack.config' );
 
config.module.rules.push(
  {
    test: /\.(gql|graphql)$/i,
    use: 'raw-loader',
  },
);
 
module.exports = config;

(Ten kod działa dla Webpack v4; dla v5 należy zamiast tego użyć Asset Modules.)

Następnie umieszczamy query GraphQL w pliku .gql:

# File graphql-documents/fetch-posts-with-author.gql
query {
  posts {
    id
    title
    author {
      id
      name
    }
  }
}

Na koniec, w kodzie bloku, importujemy plik i przekazujemy jego zawartość do fetch:

import graphQLQuery from './graphql-documents/fetch-posts-with-author.gql';
 
// ...
 
const response = await fetch(endpoint, {
  body: JSON.stringify({
    query: graphQLQuery
  )
} );

Rozwiązywanie plików .gql po stronie serwera

Plik GraphQL, który stworzyliśmy powyżej, będzie naszym jednym źródłem prawdy do pobierania danych dla bloku. Spełnia już to wymaganie po stronie klienta; zobaczmy teraz, jak zrobić to samo po stronie serwera.

Rozszerzenie Internal GraphQL Server instaluje serwer, który można wywołać w ramach naszej aplikacji, używając kodu PHP.

Internal GraphQL Server udostępnia następujące metody statyczne, za pośrednictwem klasy GraphQLServer:

  • executeQuery: Wykonuje query GraphQL
  • executeQueryInFile: Wykonuje query GraphQL zawarte w pliku (.gql)
  • executePersistedQuery: Wykonuje utrwaloną query GraphQL (podając jej ID jako liczbę całkowitą lub slug jako ciąg znaków) (wymagane jest rozszerzenie Persisted Queries)

Sygnatura executeQueryInFile wygląda następująco:

namespace GatoGraphQL\InternalGraphQLServer;
 
class GraphQLServer {
  /**
   * Execute a GraphQL query contained in a (`.gql`) file
   */
  public static function executeQueryInFile(
      string $file,
      array $variables = [],
      ?string $operationName = null
  ): Response {
    // ...
  }
}

Wywołując executeQueryInFile i przekazując wcześniej utworzony plik .gql, pobieramy dane podczas renderowania bloku dynamicznego:

use GatoGraphQL\InternalGraphQLServer\GraphQLServer;
 
$block = [
  'render_callback' => function(array $attributes, string $content): string {
    // Provide the GraphQL query file
    $file = __DIR__ . '/blocks/my-block/graphql-documents/fetch-posts-with-author.gql';
 
    // Execute the query against the internal server
    $response = GraphQLServer::executeQueryInFile($file);
 
    // Get the content and decode it
    $responseContent = json_decode($response->getContent(), true);
 
    // Access the data and errors from the response
    $data = $responseContent["data"] ?? [];
    $errors = $responseContent["errors"] ?? [];
 
    // Do something with the data
    // $content = $this->useGraphQLData($content, $data, $errors);
    // ...
 
    return $content;
  },
];
register_block_type("namespace/my-block", $block);

W ten sposób jeden plik .gql pobiera dane zasilające bloki zarówno po stronie klienta, jak i serwera.